Perlの継承について質問させてください。


先ず、カレントディレクトリがworkだとして、そこにMyModディレクトリを用意します。
以下に3つのファイルのうち、Animal.pmとBird.pmをMyModに移動、カレントディレクトリにはMain.plだけ残します。

[Animal.pm]
package Animal;
use Carp qw/croak/;
sub new{
my $pkg = shift;
bless {
name => shift || croak 'need a name'
}, $pkg;
}
1;

[Bird.pm]
package Bird;
use base qw/Animal/;
sub fly{
print "flay away!\n";
}
1;

[Main.pl]
package main;
use MyMod::Bird;
my $bird = Bird -> new('Pepe');
$bird -> fly;

この状態から、Main.plを実行すると、、、Can't locate MyMod/Bird.pm in @INC..とエラーが返ってきます。
何故でしょうか?解決策をご教授ください。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2012/01/28 16:33:22

ベストアンサー

id:TransFreeBSD No.2

回答回数668ベストアンサー獲得回数268

最小の変更としたいのであればBird.pmを下記の様にしてみてください。

package Bird;
use MyMod::Animal;
use base qw/Animal/;
~

@INCに"."(ピリオド)は含まれていますよね?
そのエラーの前に

Base class package "Animal" is empty.
    (Perhaps you need to 'use' the module which defines that package first,
    or make that module available in @INC (@INC contains:~).

のようなエラーがありませんか?
モジュールは@INCにあるパスの位置から探しますが、そこに"."(ピリオド)があるためカレントディレクトリからは探します。しかし、モジュールやソースコードの位置を基準にしては探しません。
なので、MyMod/Bird.pmで「use base qw/Animal/;」としてもカレントディレクトリ他にはないので失敗します。すると「use MyMod::Bird;」が失敗して「Can't locate」のエラーも出たような気がします。
なので一度「use MyMod::Animal;」をして(Animalモジュールではなく)MyMod::Animalモジュールを読み込み(MyMod::Animalパッケージではなく)Animalパッケージを定義すればエラーにならなかったと思います。

ただ、通常はモジュール名とパッケージ名を合わせますので、Craftworksさんのも含め、すべてのファイルのすべての「Animal」と「Bird」を変更するか、下記の様にしてMain.plでMyModディレクトリを@INCに含めます。

use lib './MyMod'
package main;
use Bird;
~
id:hiirosato

理屈まで丁寧にご説明いただき、ありがとうございました。全てのAnimal, BirdにExtend::を付加することで解決できました。

2012/01/28 16:33:07

その他の回答1件)

id:Craftworks No.1

回答回数20ベストアンサー獲得回数6

package Bird;

ではなく、

package MyMod::Bird;

としてください。

id:hiirosato

簡潔な回答をありがとうございました。TransFreeBSDさんの回答とあわせて、問題を解決することができました。

2012/01/28 16:27:31
id:TransFreeBSD No.2

回答回数668ベストアンサー獲得回数268ここでベストアンサー

最小の変更としたいのであればBird.pmを下記の様にしてみてください。

package Bird;
use MyMod::Animal;
use base qw/Animal/;
~

@INCに"."(ピリオド)は含まれていますよね?
そのエラーの前に

Base class package "Animal" is empty.
    (Perhaps you need to 'use' the module which defines that package first,
    or make that module available in @INC (@INC contains:~).

のようなエラーがありませんか?
モジュールは@INCにあるパスの位置から探しますが、そこに"."(ピリオド)があるためカレントディレクトリからは探します。しかし、モジュールやソースコードの位置を基準にしては探しません。
なので、MyMod/Bird.pmで「use base qw/Animal/;」としてもカレントディレクトリ他にはないので失敗します。すると「use MyMod::Bird;」が失敗して「Can't locate」のエラーも出たような気がします。
なので一度「use MyMod::Animal;」をして(Animalモジュールではなく)MyMod::Animalモジュールを読み込み(MyMod::Animalパッケージではなく)Animalパッケージを定義すればエラーにならなかったと思います。

ただ、通常はモジュール名とパッケージ名を合わせますので、Craftworksさんのも含め、すべてのファイルのすべての「Animal」と「Bird」を変更するか、下記の様にしてMain.plでMyModディレクトリを@INCに含めます。

use lib './MyMod'
package main;
use Bird;
~
id:hiirosato

理屈まで丁寧にご説明いただき、ありがとうございました。全てのAnimal, BirdにExtend::を付加することで解決できました。

2012/01/28 16:33:07

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません