2012-03-20 78 views
3

我遇到了一個問題,我的程序將無限循環。我縮小了這個問題,事實證明,關鍵字要求是造成這一點。因此,爲了理解這個問題,我編寫了一個簡單的hello world程序,它具有包含更大程序的確切文件結構。它有一個主文件test.pl它從test2.pm調用helloWorld。 test2.pm調用與test1.pm相同的例程。Perl關鍵字要求給出了奇怪的結果

Test.pl

#!/usr/bin/perl 
use test1; 
use test2; 
print "In test\n"; 
test2::helloWorld(); 

Test1.pm

#!/usr/bin/perl 
package test1; 
use test2; 
require "test.pl"; 
@ISA = qw (Exporter); 
@Export = qw(
    helloWorld 
    ); 

sub helloWorld { 
print "Hello world: Test1\n"; 
} 

Test2.pm:

#!/usr/bin/perl 
package test2; 
use test1; 
@ISA = qw (Exporter); 
@Export = qw(
    helloWorld 
    ); 

sub helloWorld { 
test1::helloWorld(); 
} 

這是從程序的輸出:

In test 
Hello world: Test1 
In test 
Hello world: Test1 

我想了解爲什麼它打印輸出兩次?如果我從test1.pm註釋掉 #require「test.pl」,它只打印輸出一次。

Test1.pm(需要行註釋掉)

#!/usr/bin/perl 
    package test1; 
    use test2; 
    #require "test.pl"; 
    @ISA = qw (Exporter); 
    @Export = qw(
     helloWorld 
      ); 
    sub helloWorld { 
     print "Hello world: Test1\n"; 
    } 

而這正是現在輸出:

In test 
Hello world: Test1 

我想如果我理解這一點,我可以解決我的真正的問題。感謝您在這方面:)

回答

4

當perl腳本執行任何幫助,通過require加載的文件和use至今都保存在%INC哈希,爲了防止代碼被執行一次以上,並防止無限的相互遞歸。但是,您正在從其導入的某個模塊中導入主腳本,因此它將在導入過程中運行一次,並再次作爲腳本運行。這是在你的文件的加載和執行的順序:

  1. test.pl運行,並認爲它需要加載test1.pm
    1. test1.pm被加載,它認爲它需要test2.pm
      1. test2.pm加載到加載,它認爲它需要加載test1.pm,但test1.pm已經被加載,所以它繼續。
      2. test2::helloWorld被定義,而test2.pm返回。
    2. 返回test1,現在看到需要加載test.pl
      1. test.pl中,我們嘗試加載test1.pmtest2.pm,但它們已通過require加載。
      2. 打印 「在測試」,並呼籲test2::helloWorld
    3. 早在test1.pm,定義test1::helloWorld
  2. 早在test.pl,打印 「在測試」,並呼籲test2::helloWorld
+0

比我的更好的解釋。 – Schwern 2012-03-20 19:41:43

+1

感謝您的解釋......它幫助了很多。我只想再問一件事。正如你在步驟2.2中提到的那樣,它會打印'in test'並調用'test2 :: helloWorld'。但是爲什麼它首先打印並調用函數呢?關鍵字'require'僅用於INLCLUDE文件不執行它?這是不正確的? – Richeek 2012-03-20 21:04:21

+2

'require'編譯*和*運行(使用''也是如此)。 'require'只是讀取文件和'eval'內容,而不是一次。否則像'@ISA = qw(Exporter)'這樣的事情''不會發生。 – Schwern 2012-03-21 04:55:56

3

在你的代碼中有一堆錯誤,有些錯誤不是。

  • 包的名字應該匹配.pm文件的名稱,包括案件

由於您使用的是不區分大小寫的文件系統(OS X或Windows),因此您可能會因此而部分消失。 userequire記住他們是否已經加載了一個模塊,但他們記住了文件名,而不是模塊名。當你說use test1 Perl將尋找test1.pm,但它代替加載Test1.pm。下一次,它看到use test1它看到它尚未加載test1.pm並再次加載它......再次...並再次加載它。

  • 把你的函數輸出到的變量是@EXPORT而不是@Export

案件與變量名稱有關。

  • 需要在Test1.pmTest2.pmtest.pl設置了一個循環依賴關係。

這是問題所在。 Perl在加載時尚未編譯test.plTest1.pmuse發生在編譯時)。 Test1.pm編譯,然後被要求加載test.plrequire發生在運行時)。然後完成test.pl的原始編譯並運行其代碼。

您有類似的潛在問題,因爲Test1.pm使用Test2.pmTest2.pm使用Test1.pm

這是令人困惑的,它有點像時間旅行。讓我們把它簡單化:避免循環依賴

Test1.pm沒有理由使用test.pl.一般來說,模塊不應該加載程序。

+0

感謝您的評論...實際上文件名稱與模塊名稱相同。它恰巧發生了,當我輸入名字的第一個字母得到大寫:)我肯定會改變導出爲出口,因爲這是明顯錯誤的! – Richeek 2012-03-20 21:06:15

+0

尤其是最後兩句話+1。 – chepner 2012-03-21 14:33:13