Class::Struct

もう少し現実的なアクセサメソッドの自動生成をするには……、とラクダ本を読んでみたら、標準モジュール Class::Struct が紹介されていました。C言語の構造体のような、簡単なデータクラスを作ってくれるモジュールです。
簡単な、といっても、かなり柔軟に作成できるので「perldoc Class::Struct」を読むとワクワクしてきます♪
まずは、昨日書いた Person クラスを、Class::Struct を使って書き直してみます。

package Person;
use Class::Struct;
 
struct Person => {
    name => '$',    # スカラー型
    age => '$',     # スカラー型
};
 
sub introduce {
    my $self = shift;
    print "I am " . $self->name();
    print ", " . $self->age() . " years old.\n";
}
 
package main;
$man = Person->new(name => "Somebody", age => 0);
$man->introduce();
 
$man->name("Taro");
$man->age(10);
$man->introduce();

昨日のコードに比べるとずいぶんとスッキリしましたね。(^_^)
「use Class::Struct」してモジュールを取り込むと、「struct」という関数がエクスポートされて使えるようになります。
struct 関数に、クラス名と、クラス属性・属性の型のハッシュリファレンスを渡すとコンストラクタ new と、各属性に対するアクセサメソッドを自動生成してくれます。ちなみに、クラス名を省略すると暗黙的に現在のパッケージ名が使われるとのこと。
struct 関数に渡すハッシュリファレンスは、クラスが持つ属性名がキー、その属性の型が値になります。属性の型は例えばスカラーなら '$'、配列なら '@'、ハッシュなら '%' のように、文字列で指定します。属性の型にクラス名を指定すると、そのクラス(かサブクラス)のオブジェクトリファレンスを入れられるようになります。
コンストラクタ new を呼ぶときに、属性を初期化する事ができます。(モジュール側で初期値を決めるにはどうすればいいんだろう)
もうちょっと複雑なコードを書いてみます。

package Person;
use Class::Struct;
struct Person => {
    name    => '$',
    age     => '$',
    friends => '@',
    mother  => 'Person',
    father  => 'Person',
};
 
sub introduce {
    my $self = shift;
    print "I am " . $self->name;
    print ", " . $self->age . " years old.\n";
 
    if (ref($self->friends) eq "ARRAY") {
        print "Friends: " . join(" ", @{$self->friends}) . "\n";
    }
 
    $self->mother->introduce() if $self->mother;
    $self->father->introduce() if $self->father;
}
 
package main;
my $taro = Person->new(
    name => "Taro",
    age  => 10,
    friends => ["Kenji", "Yuko"],
 
    mother => Person->new(
        name => "Taro's mother",
        age => 36,
        friends => ["Mika", "Kei"],
    ),
 
    father => Person->new(
        name => "Taro's father",
        age => 38,
        friends => ["Shota", "Hikaru"],
    ),
);
 
$taro->introduce();

Person クラスに新しく friends、mother、father という属性を増やしました。friends は友達の名前の配列、mother は母親の Person オブジェクト、father は父親の Person オブジェクトです。ツリー構造ですね。
introduce メソッドで友達の名前を挙げるようにして、父親と母親も再帰的に紹介させるようにしました。
package main では name "Taro" の Person オブジェクトを生成していますが、mother と father に新しい Person オブジェクトを直接生成して渡しています。ここでは父母までで止めましたが、書こうと思えば太郎の母の母(太郎の祖母)や父の父の父(曽祖父)など、いくらでも再帰的に書く事ができます。ツリー構造がそのまま書けて面白いですね。
以下が実行結果です。

I am Taro, 10 years old.
Friends: Kenji Yuko
I am Taro's mother, 36 years old.
Friends: Mika Kei
I am Taro's father, 38 years old.
Friends: Shota Hikaru

上手く出力できました。


実は、最初 use Class::Sturct と typo してしまって、エラーの原因がわからず30分ほど悩んでしまいました。はずかし(^_^;;