PERL 有許多內建或現成的套件(稱為package)可以使用。其實當我們開始撰寫程式的時候,PERL預設就是把我們放在 main這個套件中。
而此套件中的元素,例如變數、陣列、副程式等稱為「符號表」(symbol table),都是存在一個名為 %main 的雜湊中,這個 main 套件是程式的進入點,其他的套件都可以透過 main套件進行存取,只是我們預設都把它給忽略掉,來看以下範例:
#純量變數 $math= 40; print $main::math; # 40 #副程式 sub power { $x = shift; $y = shift; return $x ** $y; }; print &main::power(2,4); #雜湊 %s = ('name'=>'JKS', 'no'=>353); print $main::s{'name'}; #參照 $ref = sub { $x = shift; $y = shift; return $x ** $y; }; print main::&$ref(2,4);
注意上面的寫法,由上面的範例可以發現,其實我們都是在 main這個套件中操作。PERL使用兩個冒號 '::' 來取出套件中的內容。
你可以印出這個變數來檢視目前的套件
套件的寫法
套件的內容
1; #套件的結束
注意套件的結束邊界符號並不是大刮號,而是一個數字1和分號;,這個1你也能換成其他的數字。
如果把套件存成一個同名的檔案加上附檔名(.pm),就會變成PERL的模組(perl moudle)。
模組的叫用
套件的叫用有兩個方法,一個使用保留字 use,另一個使用保留字 require,這兩者的差異在於 use是在編譯時期就會載入,而require 是在執行期才會載入。所以如果有錯的話 use 在執行前就會出錯而停止,require 得執行到才會報錯。
use 模組目錄::模組名;
use 模組目錄::模組目錄::模組名;
在叫用套件時,PERL會先去查找 @INC這個廣域變數中設定的目錄,看看你要使用的模組有沒有在,你可以印出@INC來查看,例如我們常會用的 strict 模組,就存在
/usr/share/perl5/strict.pm
其中目錄/usr/share/perl5/已定義在 @INC之中。
如果你要用的模組不存在,就會出現這樣的錯誤(目錄會因系統不同而不同):
Can't locate XXX.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .)
有時會看到套件名有一個空白,後面跟一個陣列,這是使用該套件的清單(LIST),清單是指裡面的副程式或是變數等等。這裡有一點點小小的複雜,我下面會用簡單的範例來說明。
use 模組目錄::模組名 清單;
清單是指這次是要使用套件的「預設符號表」或是「需要用到的符號表」或是「定義好的符號表群組」
* 符號表:套件中的元素,例如變數、陣列、副程式等。
如果不指定,就是使用「預設符號表」,這裡要說明有點複雜,直接用下面的範例來說明。
一個自寫套件的範例
現在來撰寫一個自寫的套件,我把這些檔案放在同一個位置,由於@INC本身也包含「目前的目錄」所以可以很順利的找到我們自寫的套件。
例如下面的模組 'ip4.pm' 副程式 ip2bin 能將IP換成二進位的字串:
ip4.pm
package ip4; use Exporter; our @ISA= qw(Exporter); our @EXPORT= qw(ip2bin); our @EXPORT_OK =qw (dec2bin); our %EXPORT_TAGS = ( all => [qw(ip2bin dec2bin)]); our $VERSION = 0.01; sub ip2bin { local $ip=shift; local @seg = split('\.',$ip); local $ipbin =""; foreach(@seg){ $ipbin .= &dec2bin($_); } return $ipbin; } sub dec2bin { my $str = unpack("B32", pack("N", shift)); return sprintf("%08d",$str); } 1;
再另外寫一個程式 03.pl 去叫用我自己撰寫的套件 ip4.pm
03.pl
use ip4; print &ip2bin('10.20.40.80');
執行結果
00001010000101000010100001010000
說明 ip4.pm
第1行 定義套件名稱,這名稱要和檔名一致
第2行 套件中使用Exporter模組,這個模組讓我們能定義符號表中的私有和公有項目,類似其他語言的 public/private 物件。
第4行 繼承 @ISA 陣列中的套件,@ISA是'is a'的結合,其中列舉的是要繼承的套件
第5行 @EXPORT 陣列列舉出可供叫用的「預設符號表」
第6行 @EXPORT_OK 陣列列舉出可供叫用的「需要用到的符號表」,你必須在清單中指定才能叫用,本文下面會再說明。
第7行 @EXPORT_TAGS 雜湊列舉一些可叫用的組合,例如設定一個全部叫用'all',指定全部的副程式。
第8行 @VERSION 版本,在叫用中也可指定。
第10~18行 把ip變二進位的副程式
第20~23行 把十進位變二進位的副程式
說明 03.pl
第1行 使用套件ip4
第2行 使用套件中的副程式 ip2bin
存取權限的問題
在上例 03.pl中,如果想叫用套件 ip4.pm中的另一個副程式 dec2bin會發生什麼事?
結果出現錯誤
Undefined subroutine &main::dec2bin called at 03.pl line X.
報錯說找不到此副程式?這就是PERL的存取權限控制。由於在叫用時並沒有指定清單,因此預設只能使用這個套件中 @EXPORT中的符號表。
要解決這個問題,就得在叫用時把清單列進去:
因為 dec2bin 有寫在 @EXPORT_OK 陣列中,所以可以列進去,但不幸的原來的副程式 ip2bin 就不能用。只好一併列進去:
如果一個套件裡面有數十個符號表項目,這樣列會死人的,還好我們在 EXPORT_TAGS有定義一個群組'all',可以直接叫用(在前面加上冒號)
use ip4 qw(:all);
這樣就解決我們的問題。
套件和模組簡單的寫到這裡,讓各位有基本認識即可。事實上,會自己寫模組的機會少,用別人的模組機會多,下一個單元會寫模組的安裝和維護。
上一篇 17-參照
回到目錄 01-撰寫第一隻PERL程式
下一篇 19-模組的安裝和維護
後記:這篇真的很難寫,我一直覺得這篇是不是太難了不適合寫在這系列中,不過我還是用最簡單的認知下把他寫完了,所以篇幅有點長。