3

我开始将几个 Perl 模块迁移到Moo,但因为 setter/writer 只能有一个参数(不是吗?)而被卡住了。这也适用于强制:

package MyThing:
use Moo;
use Scalar::Util qw(blessed);
use SomeOtherThing;

has foo => (
  is => 'rw',
  coerce => sub {
      return $_[0] if blessed($_[0]) and $_[0]->isa('SomeOtherThing');
      return SomeOtherThing->new( @_ ); # does not work, because @_ == 1
  },       
);

这是一个简单的用例:

package MyApplication;
use MyThing;

$thing = MyThing->new;
$thing->foo( 'some', 'values'); # would like to have this shortcut
$thing->foo; # expected a SomeOtherThing

# must use this ugly form instead
$thing->foo( SomeOtherThing->new('some', 'values') );

有没有一种简单的方法来实现支持多参数设置的访问器?

4

2 回答 2

4

是的,使用数组引用:

use Carp;
has foo => (
  is => 'rw',
  coerce => sub {
    return $_[0] if blessed($_[0]) and $_[0]->isa('SomeOtherThing');
    ref $_[0] && ref $_[0] eq 'ARRAY' or croak "foo: arg must be a SomeOtherThing or array reference";
    return SomeOtherThing->new( @{$_[0]} );
  },       
);

之后...

$thing->foo(['some', 'values']);

如果对象需要接受键/值参数,您也可以使用 hashref。

使用完整的 Moose,您将改为编写从 ArrayRef 到 SomeOtherThing 的类型强制转换。


免责声明

我可以看到这在某些情况下很有用(例如传递 x/y 坐标而不是创建Point对象),但我会谨慎使用它。

这样做会增加类的耦合:MyThing 现在不仅依赖于 SomeOtherThing 的方法,还依赖于它的构造函数 - 如果向 SomeOtherThing 添加新字段,则可能需要更改 MyThing调用 MyThingfoo方法的所有模块。哎哟!

于 2013-03-15T15:33:30.680 回答
1

当前版本的 Moo 无法访问 setter 中的多个参数,因此我编写了一个 Perl 模块来扩展此功能。它目前是实验性的,所以请随时在 PrePAN 评论Class::Accessor::Coerce

于 2013-03-20T11:56:14.953 回答