Perl包相關

名稱衝突問題

假如在sum2.pm中使用require導入了一個代碼文件sum1.pm:數組

#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

require '/perlapp/sum1.pm';

sub sum {
    say "sum2: sum()";
}
1;

若是在sum1.pm中也有一個sum子程序:app

#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

sub sum {
    say "sum1: sum()";
}
1;

那麼在運行sum2.pm的時候,將警告子程序從新定義。由於sum2.pm首先編譯好本身的sum(),而後在運行期間require導入文件時,又再次定義sum(),將進行覆蓋操做:ui

Subroutine sum redefined at /perlapp/sum1.pm.....

這樣的名稱衝突問題,經過聲明包來解決。code

定義包和訪問包屬性

要定義一個包,只須要加上關鍵字package便可。作用域

package PKG_NAME [ VERSION_NUM ];

上面的語句用於聲明包,能夠帶上包版本號,例如package pkg1 0.01;get

例如,在sum1.pm中:hash

#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

package Sum1;

sub sum {
    say "pkg:Sum1,sum()";
}
1;

而後其它文件導入sum1.pm後,就可使用包名::屬性的方式訪問sum1.pm中的屬性,如子程序。io

#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

require '/perlapp/sum1.pm';

sub sum {
    say "file: sum2,sum()";
}

sum();         # 訪問本文件定義的sum子程序
Sum1::sum();   # 訪問包Sum1::sum子程序,括號不能少

1;

除了子程序,包中的其它非詞法做用域的屬性也能被訪問,包括:標量、數組、hash、文件句柄。例如:編譯

$Sum1::name;
@Sum1::arr;

每一個文件都至少定義在一個包內,若是沒有顯式給定package指令,則這個包默認爲main包。因此,訪問本程序文件內自身屬性的時候可使用main:: + 屬性的方式。例如在sum2.pm中:require

#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

require '/perlapp/sum1.pm';

sub sum {
    say "file: sum2,sum()";
}

sum();         # 訪問本文件定義的sum子程序
main::sum();   # 等價於上一行直接訪問sum()
Sum1::sum();   # 訪問包Sum1::sum子程序,括號不能少

1;

一個文件內多個包

通常來講,一個文件只會定義一個包。但容許一個文件定義經過包。

以下:

package Pkg1;

...code here belong to Pkg1...

package Pkg2;

...code here belong to Pkg2...

定義多個包時,從包1到包2中間的全部屬性都屬於包1。

例如,在sum1.pm中:

#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

sub sum {      # 位於默認的main包
    say "pkg:main,sum()";
}

package Sum1;  # 第一個包

sub sum {      # 位於Sum1包
    say "pkg:Sum1,sum()";
}

sum();        # 訪問的是Sum1包的sum()
main::sum();  # 訪問的是main包的sum()

package Sum2;   # 第二個包

sub sum {       # 位於Sum2包
    say "pkg:Sum2,sum()";
}

sum();        # 訪問的是Sum2包的sum()
Sum1::sum();  # 訪問的是Sum1包的sum()
main::sum();  # 訪問的是main包的sum()

1;

有一些詞語名稱老是屬於main包的: ARGV、ARGVOUT、ENV、INC、SIG、STDERR、STDIN 以及 STDOUT。有些帶有特殊標點符號的名稱(如$_,$2, $!),它們也所有屬於main。

另外,詞法變量是不能使用包名訪問的,由於使用包訪問的屬性,都是"全局"屬性。因此,要在代碼塊中訪問全局屬性,能夠加上包名:

package Sum1;
out $var="1234";
sub mysub {
    my $var;
    ...$var...;  # 訪問的是my $var
    $Sum1::var;  # 訪問的是Sum1包中的$var
}

若是將一個包聲明放進代碼塊,則出了代碼塊的域後就消失:

package Sum1;

{

    package main;
    sub sum {
        say "in main"
    }
    sum();  # 調用main中的sum
}  # 退出代碼塊,從新回到Sum1包

sub sum {code}   # 屬於Sum1包的sum子程序

包代碼塊

從perl 5.12開始,支持包代碼塊:

use v5.12;
package pkg1 {
    ...
}

package pkg2 {
    ...
}

包代碼塊至關於詞法範圍:

package Navigation {
    my @homeport = (21.283, -157.842); # 屬於包
    sub get_me_home {
        my @homeport;     # 聲明詞法變量
        ... @homeport ... # 訪問的是詞法變量
        ... @Navigation::homeport ... # 訪問的是包變量
    }
    ... @homeport ... # 訪問的是包變量
}

它等價於:

{
    package Navigation;
    my @homeport = (21.283, -157.842); # 屬於包
    sub get_me_home {
        my @homeport;     # 聲明詞法變量
        ... @homeport ... # 訪問的是詞法變量
        ... @Navigation::homeport ... # 訪問的是包變量
    }
    ... @homeport ... # refers to the package variable
}
相關文章
相關標籤/搜索