2011-09-19 8 views
5

OK。子クラスのいずれかの親クラスに設定された定数を継承しようとすると問題が発生します。インラインパッケージによる定数の継承

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

package Car; 
use Exporter qw(import); 
our @EXPORT_OK = ('WHEELS', 'WINGS'); 

use constant WHEELS => 4; 
use constant WINGS => 0; 

sub new { 
    my ($class, %args) = @_; 
    my $self = { 
     doors => $args{doors}, 
     colour => $args{colour}, 
     wheels => WHEELS, 
     wings => WINGS, 
    }; 
    bless $self, $class; 
    return $self; 
} 

package Car::Sports; 
use base qw(Car); 

sub new { 
    my ($class, %args) = @_; 
    my $self = { 
     doors => $args{doors}, 
     engine => $args{engine}, 
     wheels => WHEELS, 
     wings => WINGS, 
    }; 
    bless $self, $class; 
    return $self; 
} 

package main; 
my $obj = Car->new(doors => 4, colour => "red"); 
print Dumper $obj; 

my $obj2 = Car::Sports->new(doors => 5, engine => "V8"); 

print Dumper $obj2; 
__END__ 

エラーは次のとおりです。

Bareword "WHEELS" not allowed while "strict subs" in use at ./t.pl line 30. 
Bareword "WINGS" not allowed while "strict subs" in use at ./t.pl line 30. 
Execution of ./t.pl aborted due to compilation errors. 

今、私はいくつかの研究を行うことなく、投稿するためにここに来ていません。 1つの選択肢がuse Car qw(WHEELS WINGS)Car::Sportsにあることを理解しています。私はクラスが同じファイル内のすべてのインラインですので、私は、次のエラーを取得することを行う場合は、:

Can't locate Car.pm in @INC 

さまざまな理由のために、私は1つのファイルに私のパッケージを維持する必要があります。これを回避する方法はありますか?定数は基本的には潜在的なものであるため、通常のメソッドでは同じことが当てはまらないときに、なぜそれらをインポートする必要がありますか?

は最後に、私はまた、私はこれを行うことができます知っている:

package Car::Sports; 
use base qw(Car); 

sub new { 
    my ($class, %args) = @_; 
    my $self = { 
     doors => $args{doors}, 
     engine => $args{engine}, 
     wheels => Car::WHEELS, 
     wings => Car::WINGS, 
    }; 
    bless $self, $class; 
    return $self; 
} 

をそして、それはいいのよ...しかし、私はクラスの数を持っているし、親に名前を付けたことを、定数の継承がより一般的なようにしたいです明示的に(そして時にはそれは親クラスではなく、祖父母でもあります)。

多くのありがとうございました!

乾杯

答えて

6

回避策の一つは、ライン

 
package Car::Sports; 
use base qw(Car); 
Car->import(qw(WHEELS WINGS)); 

Car::Sportsコンストラクタでシギルを使う含めることです。

... 
wheels => &WHEELS, 
wings => &WINGS, 
... 

あなたCarクラスはその@EXPORTS_OKを定義していません実行時までリストします。コンパイル時にCar::Sportsコンストラクタが解析され、Car::Sports名前空間にWHEELSWINGSシンボルがあるはずであることをコンパイラが認識していないため、このシグニチャが必要です。あなたはまた、独自にCarクラスを定義することによって、これらの陰謀を避けることができ

package Car; 
our @EXPORT_OK; 
BEGIN {@EXPORT_OK = qw(WHEELS WINGS)} # set at compile not run time 
... 

package Car::Sports; 
use base qw(Car); 
BEGIN {Car->import('WHEELS','WINGS')} # import before c'tor is parsed 


シギルを回避する唯一の方法は、コンパイル時にCarの輸出を定義することですCar.pmファイル。次に、あなただけ自動的に実行になるだろう

use Car qw(WHEELS WINGS); 

と、コンパイル時に解析されるだろうCar.pmファイル内のすべて、AND(Car::importへの呼び出しによってトリガー)Exporter::import方法を言うと、あなたの現在のネームスペースへの希望のシンボルをインポートします。

+0

完璧!あなたは本当にこれをうまく説明し、私に何かを教えました! – wawawawa

+0

また、 'Car :: Sports'を' Car'のサブクラスにすると 'Car :: Sports'は' Car'の*メソッド*にアクセスできますが、 '&WHEELS'や'&WINGS'のような*関数は使用できません。あなたが 'Car'クラスにいくつかのメソッドを追加するまで、' use base qw(Car) 'を呼び出すことは余計です。 – mob

3

これはあなたのニーズに合わせて変更できますか?データ:: Dumperのを使用して

[...] 
    wheels => $class->SUPER::WHEELS, 
    wings => $class->SUPER::WINGS, 
    [...] 

あなたが得る:

$VAR1 = bless({ 
      'wings' => 0, 
      'colour' => 'red', 
      'doors' => 4, 
      'wheels' => 4 
      }, 'Car'); 
$VAR1 = bless({ 
      'wings' => 0, 
      'engine' => 'V8', 
      'doors' => 5, 
      'wheels' => 4 
      }, 'Car::Sports'); 
+0

素晴らしい...これをありがとう。私はSUPERで遊んでいたが、$ classは使わなかった。 – wawawawa

3

代替は、あなたがuseはまったく同じものを行うことができます:

BEGIN { 
    package Car; 
    use Exporter qw(import); 
    @EXPORT_OK = qw(WHEELS); 

    ... 

    $INC{'Car.pm'} = 1; 
} 

BEGIN { 
    package Car::Sports; 

    use Car qw(WHEELS); 
    @ISA = 'Car'; 

    ... 

    $INC{'Car/Sports.pm'} = 1; 
} 
+0

池上 - 私はあなたをPerlmonksから覚えていると思います!コメントありがとう、ありがとう! – wawawawa

0

を一般的に、何かが任意のパッケージに一定であることを暴露しますそれを定義するもの以外には、実際には悪い考えです。これは、とりわけ、コードの他の領域で一定になるような値を参照する際に、珍しいフォームを使用することに反対します。

constantモジュールは、実際に私たちは限りクラスメソッドだけで正常に動作として定数を呼び出すように、定数の話をしているという事実を隠して呼び出し形式をサポートします。

package Car; 
use constant default_wheel_count => 4; 

package Car::Sports; 

sub new { 
    my ($class) = @_; 

    return bless { 
     wheels => $class->default_wheel_count, 
    } => $class; 
} 

1が実際に定数を継承する方法ですが、それはおそらく間違ったアプローチです。これらの属性の構築を実装するクラスの定数を使用するだけで、コピペスタを排除することは実際には正しいことです。