Как передать несколько аргументов сеттеру / писателю в Perl Moo
Я начал переносить несколько модулей Perl в Moo, но застрял, потому что установщик / писатель может иметь только один единственный аргумент (не так ли?). Это также относится к принуждению:
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') );
Есть ли простой способ реализовать методы доступа, которые поддерживают настройку с несколькими аргументами?
2 ответа
Да, используйте ссылки на массивы:
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']);
Вместо этого вы также можете использовать хэш-ссылку, если объект должен принимать аргументы ключ / значение.
С полной версией Moose вы бы вместо этого написали типовое совпадение из ArrayRef в SomeOtherThing.
отказ
Я вижу, что это полезно в некоторых случаях (например, передача координат x/y вместо создания Point
объект) но я бы использовал это с осторожностью.
Это увеличивает сцепление ваших классов: теперь MyThing зависит не только от методов SomeOtherThing, но и от его конструктора - если вы добавляете новые поля в SomeOtherThing, вам может потребоваться изменить как MyThing, так и все модули, вызывающие MyThing. foo
метод. Ой!
Доступ к множественным аргументам в установщиках невозможен в текущей версии Moo, поэтому я написал модуль Perl для расширения этой возможности. В настоящее время он экспериментальный, поэтому не стесняйтесь комментировать Class::Accessor::Coerce на PrePAN.