Mooseを使用した例
次にMooseを使用してPersonとBaseballPlayerを定義する例を見ていきましょう。Mooseではblessをそのまま使用する場合に比較して、プロパティやメソッドのオーバーライドなどが簡単に定義できるようになっています。
package moosified::Person;
# (1)Mooseを読み込む
use Moose;
# (2)プロパティの定義
has 'name' => (
is => 'rw',
isa => 'Str',
default => 'none',
);
has 'age' => (
is => 'ro',
isa => 'Int',
default => 0,
);
sub introduce {
my $self = shift;
print 'My name is ' , $self->name() , ', ' , $self->age() , " years old.\n";
}
# (3)Mooseの関数を名前空間から削除し、クラスを不変化する
no Moose;
__PACKAGE__->meta->make_immutable;
1;
blessを使用した定義に比べると、newメソッドがない、プロパティ定義らしき部分に「has 'name' => (...)」と記述されている、などの違いが見て取れると思います。
Mooseを使用するには(1)のように「use Moose」でMooseを読み込みます。このときにuse strictやuse warningsも同時に設定されます。またMooseで定義されているhasなどの関数も併せて読み込まれます。Mooseでのプロパティ定義は(2)のようにhas関数を使用して行います。hasで使用可能な主要オプションには次のようなものがあります。
その他のオプションについてはMoose#EXPORTED_FUNCTIONSの項目を参照ください。
| 名前 | 指定可能な値 | 説明 |
| is | roまたはrw | プロパティへのアクセスが読み込み専用か読み書き可能かを設定する |
| isa | データ型 | プロパティへのデータ型を設定する |
| default | スカラ値またはコード | デフォルト値を設定する。スカラ値だけではなくデフォルト値を生成するコードも指定可能 |
| required | 0または1 | newメソッドで必須の場合には1を、そうでない場合には0を設定する |
| trigger | コードへの参照 | プロパティへ値が設定された場合に、指定したコードが実行される |
| clearer | クリア用メソッド名 | プロパティ値をクリアするためのメソッド名を指定すると、Mooseにより自動的にその名前でメソッドが追加される |
| predicate | 値が設定されているか判定するメソッド名 | プロパティに値が設定されているかどうかを判定するためのメソッド名を指定すると、Mooseにより自動的にその名前でメソッドが追加される |
| coerce | 0または1 | 1に設定した場合にはisaで指定した型以外の値が渡された場合に強制的な型変換を行う |
最後の部分(3)では、no Mooseを指定することでMoose関連の関数を名前空間から削除し、__PACKAGE__->meta->make_immutableでクラスを不変化させます。不変化させると、これ以降ではクラスへのプロパティの追加などはできなくなりますが、実行時にはクラスが高速に動作するようになります。
次に、Mooseを使ってPersonから継承させたBaseballPlayerを見ていきましょう。こちらの場合にも、use Mooseで始まり、最後はno Moose、__PACKAGE__->meta->make_immutableを呼び出しています。
package moosified::BaseballPlayer;
use Moose;
#(1)moosified::Personから継承させる
extends 'moosified::Person';
has 'team' => (
is => 'rw',
isa => 'Str',
default => 'none',
);
#(2)introduceをオーバーライドする
override 'introduce' => sub {
my $self = shift;
super();
print "\tAnd I belong to " , $self->team() , ".\n";
};
# 省略
Mooseで継承させるには、(1)のようにextends関数に継承元となるクラス名を指定します。メソッドをオーバーライドさせるには、(2)のようにoverrideメソッドを使用します。overrideで指定したメソッドからは、super()を使って継承元のメソッドを呼び出すことができますが、このときsuper()には引数を指定することができません(指定しても無視されます)。override指定したメソッドに引数が渡された場合には、それがそのまま継承元のメソッドに渡されます。
overrideなどの、メソッドの振る舞いを変更することができる機能はメソッド修飾子と呼ばれます。メソッド修飾子には他にもbefore、after、aroundといったものが用意されています。fooメソッドに対してbefore、after、aroundを適用した例は次のようになります。
package Example;
use Moose;
sub foo {
print "foo\n";
}
# (1)before
before 'foo' => sub { print "before foo\n"; };
# (2)after
after 'foo' => sub { print "after foo\n"; };
# (3)around
around 'foo' => sub {
my $orig = shift;
my $self = shift;
print "before foo in around\n";
# fooの呼び出し
$self->$orig(@_);
print "after foo in around\n";
};
# fooメソッドを呼び出す
Example->new->foo;
▼
before foo before foo in around foo after foo in around after foo
(1)before
beforeで指定したサブルーチンは、fooメソッドが呼び出される前に実行されます。一般的には、メソッドやプロパティの値チェックなどで使用されます。サブルーチンからの返値は無視されます。
(2)after
afterで指定したサブルーチンは、fooメソッドが呼び出された後で実行されます。一般的には、ログを記録したりする場合などで使用されます。beforeと同様にサブルーチンからの返値は無視されます。
(3)around
aroundでは、最初の引数に元のメソッド(この例だとfooメソッド)、2番目の引数にオブジェクト、それ以降では元のメソッドへの引数が渡されます。実行例からも分かるように、beforeはaroundの前、afterはaroundの後に実行されます。
aroundを使うと、引数の値によっては元のメソッドを呼び出さないこともできますし、返値を書き換えることもできるようになります。
それでは、Moose版のPersonとBaseballPlayerの動作を確認するスクリプトをmoosified_test.plという名前で定義してみます。
内容はblessed_test.plとほとんど同じで、blessed::の部分をmoosified::に変更するだけでそのまま動作します。
このスクリプトを実行し、出力される結果を確認しましょう。
$ perl moosified_test.pl
▼
Matsui
35
My name is Matsui, 35 years old.
My name is Suzuki, 36 years old.
And I belong to Mariners.
Mooseを使うとblessを使った場合に比べ、より簡潔な記述で、より多くのことを実現することができるようになりますが、その代償としてメモリ使用量の増加とコンパイル時の処理速度の低下がみられます。Moose自身にも最適化が加えられていますが、どうしても実行速度を向上させたい場合には、MouseやClass::Accessor::Fastなどの選択肢もあります。
特にMouseは、hasなどのクラス定義については、多くの部分でMooseとの互換性を保つように実装されています。
