2012-03-20 4 views
3

私のプログラムが無限ループになるという問題がありました。問題を絞り込んだところ、キーワードが必要であることがわかりましたがそれを引き起こしていました。したがって、私は問題を理解するために、より大きなプログラムとしての構造を含む正確なファイルを持つ簡単なhello worldプログラムを作成しました。それはtest.plからhelloWorldを呼び出すメインファイルtest2.pmを持っています。 test2.pmはtest1.pmから同じルーチンを呼び出します。Perlキーワードrequireが奇妙な結果を出す

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 

出力を2回印刷した理由を知りたいですか?私が #require "test.pl"をtest1.pmからコメントアウトすると、出力は1回だけ出力されます。

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

requireuseでロードされたファイルは、コードが複数回実行されないように、そしてハッシュに保持されています。無限相互再帰。しかし、インポートしたモジュールの1つからメインスクリプトをインポートしているので、インポートプロセス中に1回実行され、スクリプトとして再度実行されます。

  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. test1.pmtest2.pmをロードしようとしましたが、既にrequireでロードされています。
      2. "試験で" 印刷と
    3. test2::helloWorld戻るtest1.pmで、 "テストでは"、test.plで印刷をバックtest1::helloWorld
  2. を定義し、test2::helloWorldを呼び出して呼び出します。
+0

私よりはるかに良い説明です。 – Schwern

+1

説明をいただきありがとうございます...それは多くの助けとなりました。私はちょっとだけ質問したかった。 2.2で述べたように、 'in test 'を出力し、' test2 :: helloWorld'を呼び出します。しかし、なぜそれが印刷し、最初の場所で関数を呼び出すのですか?キーワード 'require'は、ファイルを実行しないようにINLCLUDEするために使われますか?これは間違っていますか? – Richeek

+2

'require'は*と* runsをコンパイルします(' use'も同様です)。 'require'はファイルを読み込み、内容を' eval'するだけではなく、一回だけです。さもなければ '@ISA = qw(Exporter);のようなものは起こりません。あなたのコメントのために – Schwern

3

コードにはいくつかのエラーがありますが、いくつかはそうではありません。

  • パッケージ名はケース含め.pmファイル、の名前と一致する必要があります。

大文字と小文字を区別しないファイルシステム(OS XまたはWindows)を使用しているため、部分的にそのようになっています。 userequireは既にモジュールを読み込んでいますが、モジュール名ではなくファイル名を覚えていることを覚えておいてください。 use test1と言うとき、Perlはtest1.pmを探しますが、代わりにTest1.pmを読み込みます。次回はuse test1と表示され、test1.pmがロードされていないことが確認され、再度ロードされます。

  • 関数のエクスポート先の変数は、@EXPORTではなく@Exportです。

大文字と小文字の区別はありません。 Test1.pmtest.pl又はTest2.pmを必要

  • は円形の依存関係を設定します。

これは問題です。 PerlはTest1.pm(コンパイル時にuseが発生します)をロードするときにtest.plのコンパイルを完了していません。 Test1.pmがコンパイルされ、実行時にtest.pl(実行時にrequireが発生する)がロードされます。その後、元のコンパイルtest.plが完了し、コードが実行されます。

Test1.pmTest2.pmTest2.pmTest1.pmを使用しているため、同様の潜在的な問題があります。

これは紛らわしく、時間旅行に似ています。簡単にしましょう:は循環依存関係を避けます

Test.pmにtest.plを使用する理由はありません。一般に、モジュールは決してプログラムをロードしてはいけません。

+0

ありがとう...実際にはファイル名はモジュール名と同じです。それはちょうど私が最初の文字が大文字になった名前を入力したときに起こったことです:)私は間違っているので、私は間違いなくEXPORTにエクスポートを変更します! – Richeek

+0

+1最後の2つの文特に。 – chepner