4

モジュール:./FOO/BAR/Foobar.pm

use strict;
use warnings;

package Foobar;
   our($VERSION , @ISA , @EXPORT , @EXPORT_OK , %EXPORT_TAGS , $FOO);
   BEGIN {
      require Exporter;
      @ISA       = qw(Exporter);
      @EXPORT_OK = qw(&foo);
   }

   sub foo {
      print "Loaded\n";
      $FOO = q{some val};
   }

1;

プログラム:./Caller.pl

#!/usr/bin/perl

   use strict;
   use warnings;

   use FOO::BAR::Foobar qw/foo/;

   Foobar::foo();  # works
   foo();          # errors out - can't find &main::foo

私が試したことをすべてリストしますが、たくさんあります。BEGIN を削除し、PerlMonks の [古い] 投稿で提案されているように、他のいくつかのことを行いました。

パッケージ名がモジュール名と同じ名前である場合、エクスポーターはデフォルトで特定の方法で動作することをどこかで読んだことがあると思います。モジュールをサブディレクトリに置くと、その動作が変わる可能性があるかどうかはわかりません(?)。しかし、私は私がどのように失敗したかを知りたがっています。

4

2 に答える 2

5

モジュールがFOO/BAR / Foobar.pmにある場合、パッケージ名は。である必要がありますFOO::BAR::Foobar

&また、@EXPORT_OK配列から記号を削除します。

于 2012-06-21T13:02:50.107 に答える
4

choroba の回答に加えて、 Sherm Pendleyによるこの投稿を見つけました。これは、何年も前に読んだ投稿と同じだと思います。

関数をエクスポートする非 OO モジュールでは、Exporter がその機能を実行するために同じでなければなりません。モジュールを use() すると、「Foo」と呼びましょう。基本的には、次の手順が行われます。

BEGIN {
   require Foo;
   import Foo qw(args);
}

2 番目のステップはオプションです。モジュール Foo に import() 関数がない場合でも、use() は成功します。

さて、パッケージ Bar が Foo.pm にあるとしましょう。Foo.pm は問題なく require() によってコンパイルされます。そのコードはパッケージ Bar にあるため、明示的に宣言またはエクスポーターから継承された import() 関数もそのパッケージにコンパイルされます。

しかし、use() は依然としてパッケージ Foo の import() 関数を呼び出そうとします。さらに悪いことに、 import() はオプションであるため、黙って失敗します。ユーザーが何か問題が発生したことを知る唯一の手がかりは、完全に指定されたパッケージ名、つまり Bar::baz() がなければ、パッケージ Bar で宣言された関数はどれも使用できないということです。現在のパッケージでのそれらのエイリアス。

その他のことは、ファイル名 = パッケージの規則にも依存する可能性があります。たとえば、perldoc を見てみましょう。モジュールのユーザーがモジュールのドキュメントを取得するために「perldoc Foo」を実行すると、Foo.pm にあるドキュメントが読み込まれます。これらのドキュメントに「Bar」という名前のパッケージが記載されている場合、ユーザーは混乱するでしょう。

モジュールが「純粋な」オブジェクト指向であり、何もエクスポートしない場合でも、確立された規則に従うことで混乱を避けることができます。メンテナンス プログラマーが 1 年後にスクリプトを見て、次のようになると想像してください。

use Foo;
my $bar = Bar->new();

Foo.pm で定義されたクラス Bar を見るのはあまり直感的ではありません。

いいえ、理論上は必要ありません。しかし、それらに同じ名前を付けるという慣習は非常に広く守られているため、実際には多かれ少なかれ必要とされています.


したがって、モジュールごとに複数のパッケージがある場合、ファイルと同じ名前を共有するものだけがその変数/関数をエクスポートできるようです。他のパッケージ (?) 用に独自のインポート関数を作成すれば、それを機能させることができると思います。

とにかく、私の例では、パッケージを階層ツリー全体と呼びたくない場合は、lib を設定できます。

use lib './FOO/BAR';
use Foobar qw/foo/;   # instead of "use FOO::BAR::Foobar"

これは、代わりにFoobar.pmand を内部に保持できることを意味しますpackage Foobarpackage FOO::BAR::Foobar

于 2012-06-21T13:45:57.870 に答える