2010-06-04 76 views
6

從一切我已經使用Perl模塊讀取,基本用法是:的Perl - 封裝/模塊問題

  • .pm擴展,其中包括聲明package <name>,其中<name>是的文件名模塊文件沒有擴展名的模塊。
  • 使用模塊的代碼文件包含語句use <name>;

我正在編寫的應用程序有一個主代碼腳本,它使用了大約5個模塊。我忘記了在模塊中包含package <name>語句,但是我的代碼在use <name>語句中仍然運行良好。我開始接收Undefined subroutine錯誤與其中一個模塊,所以我將package語句添加到每個模塊。現在其他模塊停止工作。是什麼賦予了?

實施例:

mainapp.pl

#!/usr/bin/perl 
use UtyDate; 
my $rowDate = CurrentDate("YYYYMMDD"); 

UtyDate.pm

#!/usr/bin/perl 
package UtyDate; 
sub CurrentDate 
{ 
    #logic 
} 
return 1; 

當我運行上面的代碼,我得到的錯誤Undefined subroutine &main::CurrentDate called at...。但是,如果我從UtyDate.pm中刪除package UtyDate;行,則不會出現錯誤。這種情況存在幾個但不是全部我的模塊。

顯然還有更多的代碼我沒有顯示,但我很困惑我沒有顯示的任何代碼可能會影響我在這裏顯示的包/使用構造。

回答

10

當你使用一個模塊,在該模塊中的代碼在編譯時運行。然後在該模塊的包名稱上調用導入。所以,use Foo;是因爲所有的代碼被包main,這是所使用的主要的應用程序代碼下執行BEGIN { require Foo; Foo->import; }

你的代碼工作沒有package聲明相同。

當您添加package聲明時,它停止工作,因爲您定義的子例程不再在main中定義,而是在UtyDate中定義。

您可以使用完全限定名稱UtyDate::CurrentDate();訪問子例程,也可以在模塊use中將子例程導入當前名稱空間。

UtyDate.pm

package UtyDate; 
use strict; 
use warnings; 

use Exporter 'import'; 

# Export these symbols by default. Should be empty!  
our @EXPORT =(); 

# List of symbols to export. Put whatever you want available here. 
our @EXPORT_OK = qw(CurrentDate AnotherSub ThisOneToo); 

sub CurrentDate { 
    return 'blah'; 
} 

sub AnotherSub { return 'foo'; } 

主程序:

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

use UtyDate 'CurrentDate'; 

# CurrentDate is imported and usable.  
print CurrentDate(), " CurrentDate worked\n"; 

# AnotherSub is not 
eval { AnotherSub() } or print "AnotherSub didn't work: [email protected]\n"; 

# But you can still access it by its fully qualified name 
print UtyDate::AnotherSub(), " UtyDate::AnotherSub works though\n"; 

Exporter文檔的更多信息。

+2

OP應該閱讀' perlmod'(http://search.cpan.org/perldoc/perlmod)首先作爲了解'Exporter'中出現的情況的先決條件 – mob 2010-06-04 22:13:55

+0

很好的解釋,謝謝。我見過出口商在我看到的一些例子中使用過,但不是全部,所以我認爲它是無關的。 我會看看文件太mobrule,謝謝。 – brydgesk 2010-06-04 22:29:32

3

您缺少導出程序的perl標頭代碼。您將需要添加類似下面的包語句下方的PM文件的開頭一句:

package UtyDate; 
BEGIN { 
    use Exporter(); 
    use vars qw($VERSION @ISA @EXPORT); 
    $VERSION = "1.0.0"; 
    @ISA = qw(Exporter); 
    @EXPORT = qw(&CurrentDate); 
} 

請參閱此鏈接:http://perldoc.perl.org/Exporter.html#DESCRIPTION

+0

根據http://p3rl.org/Exporter#Good_Practices進行編輯或更好地使用[Sub :: Exporter](http://p3rl.org/Sub::Exporter)。 – daxim 2010-06-04 22:06:18

1

或者格雷的建議,你可以這樣做:

use UtyDate; 
UtyDate::CurrentDate(...); 
0

除了使用出口商,因爲灰色指出,你可以(難看,但作品)也呼籲與模塊名稱的功能..

你福nctiond /程序不工作,因爲他們現在是在一個differen命名空間(由模塊名稱來定義)

use UtyDate; 

UtyDate::CurrentDate() 
+1

這並不難看,這是調用不是以OO風格編寫的函數的標準方式。 – Ether 2010-06-04 21:31:27

+0

命名空間由'package'調用定義,而不是模塊的名稱。這只是一個約定(儘管很好),包名和模塊名是相同的。 – mob 2010-06-04 22:10:29

+0

@其他:標準與「不難看」不一樣,我擔心。此外,與格雷的'解決方案'相比,我的意思是'醜陋',這需要對已經編寫的代碼進行少得多的修改('很多改變'就是我認爲'醜陋',如:改變錯誤錯誤YMMV – lexu 2010-06-05 06:09:46