使用 Moose 程式設計/解決的問題/訪問器
Perl 有兩種聚合(非標量)資料型別:陣列和雜湊(即關聯陣列),它們通常用作物件的基資料結構。一個更嚴重的問題是這些資料型別都不是物件。例如,本機陣列和雜湊支援不允許您在向雜湊寫入新的鍵值對時或將新元素推入陣列時接收事件觸發器。可以使用 Perl 的 tie() 機制來實現這一點,但 tie() 會帶來嚴重的效能損失。Perl 確實增強了 C 樣式的固定大小陣列 - 一個簡單的連續記憶體塊,透過索引定址 - 以便它可以根據需要增長或收縮,但出於效率原因選擇了僅實現基本操作。[1]
兩者中的一種可能更適合一項任務,而不適用於另一項任務,但這並不重要。使用 Moose,您的程式不會直接繫結到 Perl 資料結構。
傳統上,Class::Accessor 在這個領域做了最多的事情,我們很快就會看到這一點。它解決的問題很大也很簡單,而且它沒有過度實現:如果你有一個雜湊,你不想插入一個 key: foobar,你該怎麼辦?你只需將雜湊 bless 到一個物件中,並說明應該生成哪些訪問器。現在這個“雜湊”充當你的模組可以包裝的簡化模型,以實現程式的目標。當呼叫一個不相關的函式時,perl 會意識到它無法將方法解析到匹配的子程式,並報錯。[2]
仔細看看這段程式碼的簡潔性。
package OldWay;
use strict;
use warnings;
use base 'Class::Accessor'; ## or C::A::Fast, or C::A::More, et al.
BEGIN { Class::Accessor->mk_accessors( qw/ foo bar baz / ) }
sub new {
my $class = shift;
bless {}, $class;
}
package main;
use strict;
use warnings;
my $obj = OldWay->new;
## These work
$obj->foo( 1 );
$obj->bar( OldWay->new );
$obj->baz( 'foo' );
## Anything else will die
$obj->quz( 1 ); #die
在這裡,我們建立了一個物件,本質上是一個只允許三個鍵的雜湊。這個雜湊的 getter 和 setter 與底層 perl 雜湊中的鍵直接相關。請記住,Perl 物件非常簡單。複雜性留給程式設計師作為練習。
說實話,Moose 不僅僅是 Class::Accessor 的替代品。因此,它不會與 Class::Accessor 的簡潔性競爭。然而,在本節中,我們將看到 Moose 的類似物。[3]
package NewWay;
use Moose;
has 'foo' => ( isa => 'Value', is => 'rw' );
has 'bar' => ( isa => 'Value', is => 'rw' );
has 'baz' => ( isa => 'Value', is => 'rw' );
# or just
# has [qw/ foo bar baz /] => ( isa => 'Value', is => 'rw' );
package main;
use strict;
use warnings;
my $obj = NewWay->new;
## Rest of the module is the same..
## These work
$obj->foo( 1 );
$obj->bar( NewWay->new );
$obj->baz( 'foo' );
## Anything else will die
$obj->quz( 1 ); #die
非常簡單。到目前為止,沒有任何語法真正需要解釋——但在下一節中,我們將解釋。
為了清晰起見,以及那些無法透過示例學習的人
has 是少數幾個 Moose 關鍵字之一,它開始了一個宣告語句的 Moose 表示式。
在 has 的上下文中,isa 指的是物件的 TypeConstraint。Moose 具有內建的型別系統,這個關鍵字(將在下一章中進一步解釋)指定了該屬性將接受哪些值。
在 has 的上下文中,is 指的是要建立的訪問器型別。值為 rw 將指示 Moose 生成 setter 和 getter,而值為 ro 將只生成 getter。