你是否覺得Perl中關於模塊的文檔有些難懂?好的,這里有一個世界上最簡單的模塊,它將用於展示(demonstrate)Exporter模塊所有的特性,另外還有一段使用這個模塊的腳本。同時,我們也會給出一個有關於@INC的簡短說明,最后,還要講一下有些關於using warnings和use模塊的使用。
下面是這個模塊的內容:
MyModule.pm
package MyModule; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(func1 func2); %EXPORT_TAGS = ( DEFAULT => [qw(&func1)], Both => [qw(&func1 &func2)]); sub func1 { return reverse @_ } sub func2 { return map{ uc }@_ } 1;
首先,我們將通過聲明 "package" 名字來獲得一個名字空間。這將確保模塊中的方法與變量,和調用他們的代碼所分隔開來。
use strict在模塊中是一個非常好的做法,這將使Perl對使用全局變量做出一定的約束。
我們需要用Exporter模塊來將我們的函數從MyModule::namespace輸出到main::namespace,讓使用MyModule的程序可以使用這些函數。
為了use strict,我們必須使用use vars來聲明一些變量。當然,在5.6版本以上我們還可以使用our來聲明變量。
我們現在設置一個$VERSION數值,然后通過使用@ISA來使得Exporter成為MyModule的一部?。想要了解@ISA是什么以及如何使用等細節,請參考"perlboot"。
@EXPORT包含了我們需要默認輸出的函數列表。在這里,它是空的。一般來說,你通過默認的使用@EXPROT輸出的越少越好。因為調用該模塊的程序中,有可能存在與其中函數相之沖突的函數或者代碼。如果程序需要調用某個指定的函數,那么,就請就讓它主動請求。
@EXPORT_OK包含了我們在調用時需要輸出的函數列表,我們只輸出了&func1和&func2,這種方法要優先於盲目地使用@EXPORT來輸出函數。你也可以輸出像$CONFIG這樣全局的、不是用my定義的字義范疇的變量。(可參考用 "our" 或者 use vars來聲明全局變量)
%EXPORT_TAGS.為了方便起見,我們定義了兩套輸出標簽。‘:DEFAULT’標簽只輸出&func1;‘:Both’標簽則輸出&func1和&func2。這個哈希表存儲指向數組引用的標簽。注意:在這里的數組是匿名的。
最后,我們需要在模塊結尾加上一個“1;”。因為當perl裝載一個模塊時,它會實現查看這個模塊是否能在最后返回一個真值,並且據此判斷該模塊是否已裝載成功。當然,你可以在最后面添加任何真值(參看 "Code::Police" ),但其中1是最方便的。
MySciprt.pl(使用MyModule的一個例子)
#!/usr/bin/perl -w use strict; # you may need to set @INC here (see below) my @list = qw (J u s t ~ A n o t h e r ~ P e r l ~ H a c k e r !); # case 1 # use MyModule; # print func1(@list),"\n"; # print func2(@list),"\n"; # case 2 # use MyModule qw(&func1); # print func1(@list),"\n"; # print MyModule::func2(@list),"\n"; # case 3 # use MyModule qw(:DEFAULT); # print func1(@list),"\n"; # print func2(@list),"\n"; # case 4 # use MyModule qw(:Both); # print func1(@list),"\n"; # print func2(@list),"\n";
正如上面所見,我們在MyScript.pl中使用了MyModule。把中間的注釋符號都去掉來看看會發生什么。一次都去掉即可。
Case 1: 因為我們的模塊默認什么都沒有輸出(沒有輸出&func1和&func2),所以我們會得到一個他們在main:: namespace中不存在的錯誤。
Case 2: 這個運行正常。我們讓模塊輸出了&func1,於是我們可以正常使用它。盡管我們沒有輸出&func2,但是我們使用的是 &func2完整的包路徑,所以它也可以正常工作。
Case 3: ‘:DEFAULT’標簽應該輸出&func1,所以你應該希望返回一個缺少&func2函數的錯誤。但事實上perl卻偏偏找上了&func1的麻煩(錯誤信息提示未定義&func1函數)。恩,這里怎么了呢?原來,DEFAULT這個標簽名字是特殊的,在我們的模塊中,%EXPORT_TAGS哈希表它會被自動設置成這樣DEFAULT=>\@EXPROT.也就是說,DEFAULT默認導出的是來自@EXPROT數組的函數。
Case 4: 我們指定通過‘:Both’標簽實現兩個函數都輸出,他實現了。 *關於@INC的注意事項* 當你提交一個use MyModule的時候,就會指示perl去搜索@INC數組中是否有此模塊名。@INC通常包含:
/perl/lib /perl/site/lib .
“.”這個目錄表示當前的工作目錄。核心模塊是安裝在perl/lib目錄中,非核心模塊安裝在perl/site/lib目錄中。你可以向@INC中添加自定義目錄。像下面這樣:
BEGIN { push @INC, ’/my/dir’ } # or BEGIN { unshift @INC, ’/my/dir’ } # or use lib ’/my/dir’;
我們需要使用BEGIN塊在編譯時向@INC中添加值,此時是perl檢查模塊的時刻。
如果你等到程序被編譯的時候就太晚了, perl會拋出一個異常,說“在@INC中無法找到MyModule”.使用push還是unshift方法添加值的區別是,perl搜索@INC的順序是從@INC中的第一個目錄開始的。如果你在/perl/lib/、/perl/site/lib/和./中都有一個MyModule模塊的話,那么 /perl/lib中的模塊將首先被找到並使用。use lib用法可以起到和BEGIN{unshift @INC,$dir}一樣的效果-請參看"perlman:lib:lib":http://www.perlmonks.org/?node= perlman%3Alib%3Alib . *use Foo::Bar意味着什么* use Foo::Bar並不意味着在@INC的目錄中尋找一個叫做Foo::Bar.pm的模塊文件。它的意思是在@INC的目錄中尋找一個叫做‘Foo’的 “子目錄”,然后在其中找一個叫做“Bar.pm”的“模塊”。現在,如果我們成功"use"了一個模塊,那么我們就可以通過完整的包路徑語法&PACKAGE::FUNCTION使用這個模塊中的所有函數。當我們說&Foo::Bar::some_func的時候,我們指的是“包的名字”而不是那個在use中曾使用的包含路徑的文件名。這會允許你可以在一個use過的文件中包含很多包名字。實際使用中這些名字通常是相同的。
use warnings;
你應該打開warnings來檢測你的模塊,因為它可以檢測出很多細微的錯誤。你可以通過在測試模塊代碼中添加-w參數來打開警告選項。如果你在模塊中添加了use warnings,那么你的模塊必須要求運行在perl5.6以上,否則不支持。如果你在模塊的頂端添加了$^W++,那么你將會在全局范圍內打開警告選項-這將影響到其他模塊,你最好只在你自己的程序中這么使用,因為這略顯霸道了一些。這有一個專家寫的叫做"tye":http: //www.perlmonks.org/?node=tye 的代碼來測試警告選項,但沒有直接將它包含進他/她自己的模塊中。希望這些會講清楚它是怎樣工作的。
From: http://www.perlchina.org/archive/archive.php?action=archive&page=33