UNIVERSAL::can
UNIVERSALは全てのクラス共通の祖先ですが、それを利用して UNIVERSAL クラスに定義されている便利なメソッドを、どんなオブジェクトからでも呼び出す事ができます。
UNIVERSAL::can は、指定したメソッドのリファレンスを得る事ができます。もしメソッドが存在しない場合は undef を返すので、「オブジェクトはこのメソッドを実行できるか」を調べたい時に便利です。
使ってみました。
package Dog;
sub new { bless {}, shift }
sub bark { return "Bow-wow!" }
package Cat;
sub new { bless {}, shift }
sub meow { return "Meow, meow..." }
package main;
$pochi = Dog->new();
$tama = Cat->new();
if ($pochi->can("bark")) {
print "Pochi barks: ", $pochi->bark(), "\n";
} else {
print "Pochi can't bark.\n";
}
if ($pochi->can("meow")) {
print "Pochi meows: ", $pochi->meow(), "\n";
} else {
print "Pochi can't meow.\n";
}
if ($tama->can("bark")) {
print "Tama barks: ", $tama->bark(), "\n";
} else {
print "Tama can't bark.\n";
}
if ($tama->can("meow")) {
print "Tama meows: ", $tama->meow(), "\n";
} else {
print "Tama can't meow.\n";
}
Dog クラスは bark メソッドを、Cat クラスは meow メソッドをそれぞれ持っています。
Dog オブジェクトである $pochi と、Cat オブジェクトである $tama が、それぞれ bark と meow を持っているか can で確かめています。
以下が実行結果です。
Pochi barks: Bow-wow! Pochi can't meow. Tama can't bark. Tama meows: Meow, meow...
ちゃんと判別できていますね。
継承したメソッドの場合はどうなるのでしょうか。
package Animal;
sub new {
my ($class, $name) = @_;
bless \$name, $class;
}
sub sleep {
my $self = shift;
print "$$self is sleeping.\n";
}
sub eat {
my ($self, $food) = @_;
print "$$self is eating $food.\n";
}
package Human;
@ISA = qw(Animal);
sub sleep {
my $self = shift;
print "$$self is sleeping ... zzz ZZZ\n";
}
package main;
$palmo = Human->new("Palmo");
if ($palmo->can("sleep")) {
$palmo->sleep();
} else {
print "Palmo can't sleep.\n";
}
if ($palmo->can("eat")) {
$palmo->eat("Spaghetti");
} else {
print "Palmo can't eat.\n";
}
if ($palmo->can("fly")) {
$palmo->fly();
} else {
print "Palmo can't fly.\n";
}
Human クラスは Animal クラスを継承しています。sleep メソッドはオーバーライドしています。
Human オブジェクトを生成して $palmo に代入し、sleep、eat、fly メソッドが実行できるか確かめています。
以下が実行結果です。
Palmo is sleeping ... zzz ZZZ Palmo is eating Spaghetti. Palmo can't fly.
継承したメソッド eat も can で検出できるようですね。(^_^)