你是否覺得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 -wuse 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’ }# orBEGIN { unshift @INC, ’/my/dir’ }# oruse 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