使用 Moose 编程/难点/Moose 与 Moose
外观
在使用 Moose 一段时间后,你最终会发现自己拥有了一系列想要重复使用的类。不幸的是,Moose 不会让在 Moose 内部使用这些 Moose 类变得容易。以下是在 Moose 内部执行的一些困难任务[1]。
在这些示例中,MooseObj 是一个 Moose 对象。
- isa => ArrayRef[ MooseObj ]
- 没有语法糖来方便创建 MooseObj。
- 无法从
$self->MooseObj( [{constructor_args1}, {constructor_args2}] )
轻松强制转换。
- isa => 'MooseObj'
- 没有对 MooseObj 的语法自动装箱,你不能执行以下操作:
$self->foo->new( {constructor_args} )
。 - 没有隐式方法绕过 MooseObj 的创建并设置其访问器。更多信息请参见 一对一自动构建。
- 没有对 MooseObj 的语法自动装箱,你不能执行以下操作:
如果你不关心 MooseObj,只关心内部的访问器怎么办?子对象可能只是作为更多访问器的逻辑分组,如以下示例所示。
package Address;
use Moose;
has 'street' => ( isa => 'Str', required => 1, is => 'ro' );
has 'city' => ( isa => 'Str', required => 1, is => 'ro' );
has 'zip' => ( isa => 'Str', required => 1, is => 'ro' );
has 'state' => ( isa => 'Str', required => 1, is => 'ro' );
package USProfile;
use Moose;
has 'workAddress' => ( isa => 'Address', is => 'ro' );
has 'homeAddress' => ( isa => 'Address', is => 'ro' );
即使 Moose 非常努力地替换和抽象掉许多 Perl 的基本类型,这里与使用 Address 哈希相比,它使工作变得困难。以下是一些明显的困难。
- 你不能跳过创建新Address对象
- 语法
$USProfile->workAddress->street('1234 FooStreet')
无效。 - 语法
$USProfile->workAddress->{street} = '1324 FooStreet'
将是有效的(假设workAddress是哈希)。
- 语法
- 你可能希望组件类Address要求其子属性,但没有办法在该类用作另一个类的子类时,禁用这些
requires=>1
。- 语法
has 'workAddress' => ( isa => 'Address', is => 'ro', default => sub{Address->new} );
无效。 - 由于与
is=>'ro'
类似的问题,这在这个情况下并不十分有用。
- 语法
本节正在重写 现在显然应该发生一些漂亮的事情来方便创建电子邮件。在这里进行的任何工作都会极大地促进 Moose 在基于令牌的系统中的应用,例如 XML,你可以在 Moose 中轻松地建模一个一级树,然后将其拉入另一个 Moose 类以创建多级文档。以下是尚未实现的伪代码。
my $person = USProfile->new;
## Hack a handles new into the Email code, which calls its own constructor
my $email = $person->email->new({ (constructor) })
## Still permit some sort of construction that suffices the required
## obviously a no-go if you have it embedded in an ArrayRef or HashRef
my $person => USProfile->new({state=>'TX', email=>{[moose_args=>]constructor args} }
可能需要为继承自 Moose::Object 的事物设置一组 AttributeHelpers。
另一种实现此目的的方法类似于(由 steven 提供)。
has hash => (
is => "ro"
, default => sub { blessed(shift)->new }
, lazy => 1
);
my $h = Hash->new;
$h->hash->hash->hash;
print $h->dump;'
这里有一些问题。
blessed(shift)->new
应该是isa=>
的值。- 它不适用于
isa
,这些isa
有required=>1
,必须有一些方法自动构建,或者发送构造函数参数。
- ^ 困难或过于冗长。