跳轉到內容

使用 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

[編輯 | 編輯原始碼]

說實話,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

has 的上下文中,isa 指的是物件的 TypeConstraint。Moose 具有內建的型別系統,這個關鍵字(將在下一章中進一步解釋)指定了該屬性將接受哪些值。

另請參閱:has

has 的上下文中,is 指的是要建立的訪問器型別。值為 rw 將指示 Moose 生成 setter 和 getter,而值為 ro 將只生成 getter。

  1. ^ 除非你顯式地製作了一個 sub AUTOLOAD {},否則我們不要理會這個例外。
  2. ^ 固定是指你可以push到陣列的兩端。不能保證新資料與舊資料是連續的。當你用 perl 程式設計時,你不應該在低階思考,不用擔心會發生什麼,只要知道它會起作用。
  3. ^ 當然,使用 Moose::Tiny,你可能會得到一個比 Class::Accessor 更強大、更簡潔的替代方案,但我們將在本書的後面部分討論 MooseX:: 和替代方案。
華夏公益教科書