2

これは興味深い Perl の動作です。(少なくとも私には:))

私は 2 つのパッケージを持っておりPACKAGE1PACKAGE2どちらが同じ名前の機能をエクスポートしますMethod1()

これと同じ関数をエクスポートするパッケージが非常に多いためuse、Perl ファイル内のすべてを -ing するのは面倒です。INCLUDES.pmしたがって、これらの s を持つ一般的なインクルード ファイルを作成しましたuse

含まれるもの.pm:

use PACKAGE1;
use PACKAGE2;

1;

パッケージ1.pm:

package PACKAGE1;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw (
          Method1
);

sub Method1{
print "PACKAGE1_Method1 \n";
}

1;

パッケージ2.pm:

package PACKAGE2;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw (
    Method1
);

sub Method1{
    print "PACKAGE2_Method1 \n";
}

1;

Tests.pl:

##################first package################
package Test1;
use INCLUDES;
my @array = values(%INC);
print  "@array  \n";

Method1();

##################second package################
package Test2;
use INCLUDES;  #do "INCLUDES.pm";
my @array = values(%INC);
print  "@array  \n";

Method1();

動機は、Method1()Perl ファイルで最新のパッケージのみを使用する必要があるということです。

出力は私を驚かせます。両方のMethod1()呼び出しTests.plが成功するはずです。ただし、最初の呼び出しのみがMethod1()実行され、2 番目のMethod1()呼び出しは「未定義」と表示されます。

出力:

C:/Perl/site/lib/sitecustomize.pl PACKAGE1.pm C:/Perl/lib/Exporter.pm PACKAGE2
.pmINCLUDES.pm

PACKAGE2_Method1

C:/Perl/site/lib/sitecustomize.pl PACKAGE1.pm C:/Perl/lib/Exporter.pm PACKAGE2
.pm INCLUDES.pm

Undefined subroutine &Test2::Method1 called at C:\Temp\PackageSample\Tests.pl line 15.

誰かがこれについて何か答え/見解を持っていますか?

実際のシナリオ:

複数の Perl モジュールのメソッドは同じ名前になります。ただし、優先度の高い perl モジュールのメソッドのみを使用する必要があります。

たとえば、&が のみを含む場合PACKAGE1、次から使用する必要があります&から使用する必要がありますMethod1(), Method2()PACKAGE2Method1()Method1()PACKAGE2Method2()PACKAGE1

基本的に、プリファレンスに基づいてモジュール間の階層を実現したいと考えています。これには何か方法はありますか?

4

2 に答える 2

4

Perlでは、use Moduleと同等です

BEGIN { require Module; Module->import; }

ただしrequire、必要なモジュールのリストをキャッシュします。Perlプロセスごとに1回だけモジュールをロードします。したがって、最初の人だけuse IMPORTSが何かをします。IMPORTSモジュールにはメソッドがないため、再度実行してimportも何も起こりませんuse

あなたが何を成し遂げようとしているのかよくわかりません。おそらく、IMPORTSモジュールは、必要importな関数をエクスポートするメソッドを備えた実際のパッケージである必要があります。そうすれば、それぞれuse IMPORTSがそれを呼び出したパッケージに関数をエクスポートします。

于 2013-02-02T05:43:11.310 に答える
3

use MyPackageと同等BEGIN{ require MyPackage; MyPackage->import }です。importExporter から継承すると、「エイリアシング」機能を実行するクラス メソッドが設定されます。

問題は、INCLUDES モジュールがモジュールを正しく再エクスポートしないことです。これは、関数を呼び出し元の名前空間にインポートするプロセスであるため、重要です。これを自分で作成するのは難しくありませんが、この目的のための便利なモジュールImport::Intoがあります。

これは単一のファイルに含まれる例です。複数に再展開するのは簡単なはずです。唯一の重要な違いは、Includes モジュールにあります。他にもいくつかの表面的な変更を加えましたが、それらは私の好みに合っています。

#!/usr/bin/env perl

use strict;
use warnings;

package PACKAGE1;

use parent 'Exporter';
our @EXPORT = qw(Method1);

sub Method1 {
  print "PACKAGE1_Method1 \n";
}

package PACKAGE2;

use parent 'Exporter';
our @EXPORT = qw(Method1);

sub Method1 {
  print "PACKAGE2_Method1 \n";
}

package Includes;

use Import::Into;

# uncomment in mulitple files
#use PACKAGE1 ();  # prevent import
#use PACKAGE2 ();  # ditto

sub import {
  my $class = shift;
  my $caller = caller;

  PACKAGE1->import::into( $caller );
  PACKAGE2->import::into( $caller );
}

package Test1;
Includes->import; # in seperate files replace with `use Includes;`

Method1();

package Test2;
Includes->import; # ditto

Method1();

実際の例は、utf8::allこのメカニズムを広範囲に使用して、多くの Unicode を呼び出し元パッケージにロードするモジュールです。

編集

Includesモジュールから特定のものをインポートできるようにするには、それを継承し、それを作成しExporterて、意図したとおり@EXPORT@EXPORT_OK実行することができます。Import::Intoそれ以外の場合は、バンドルのようなものを続けて作成できます。

sub import {
  my $class  = shift;
  my $bundle = shift;

  my $caller = caller;

  if ($bundle eq 'Bundle1') {
    PACKAGE1->import::into( $caller );
    ... # other things in Bundle1
  } elsif ($bundle eq 'Bundle2') {
    PACKAGE2->import::into( $caller );
    ... # other things in Bundle2
  }
}

次に、テストモジュールで

use Includes 'Bundle1';

要するに、独自のimport方法を作成することはそれほど難しくなく、すべてが魔法のようですExporter. シンボル テーブルの操作について学べば、それは必要ありませんImport::Into。ただし、少し高度なトピックです。これは、Perl 時代のずっと前に私がそれについて尋ねた質問です: Demystifying the Perl glob (*)

とはいえ、継承とポリモーフィズムのオブジェクト指向の概念がうまく機能する場合は、そのルートも調査することをお勧めします。その例を次に示します。

#!/usr/bin/env perl

use strict;
use warnings;

package PACKAGE1;

sub Method1 {
  my $class = shift;
  print "PACKAGE1_Method1 \n";
}

sub Method2 {
  my $class = shift;
  print "PACKAGE1_Method2 \n";
}

package PACKAGE2;

# if multiple files use this
#use parent 'PACKAGE1';
# rather than
our @ISA = 'PACKAGE1';

# any methods in PACKAGE2 will override those declared in PACKAGE1 

sub Method1 {
  my $class = shift;
  print "PACKAGE2_Method1 \n";
}

package Test1;

# in seperate files need to use
#use PACKAGE2;

PACKAGE2->Method1();
PACKAGE2->Method2();

package Test2;

# ditto
#use PACKAGE1
#use PACKAGE2

PACKAGE2->Method1();
PACKAGE2->Method2();

# you can still use PACKAGE1 and get the originals
PACKAGE1->Method1();
PACKAGE1->Method2();

パッケージがなく、シンボルが名前空間Includesにインポートされていないことを確認してください。から継承し、独自のメソッド宣言でメソッド宣言をオーバーライドしないためです。Test*PACKAGE2Method2PACKAGE1

于 2013-02-02T06:01:16.543 に答える