Как передать несколько аргументов сеттеру / писателю в 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.

Другие вопросы по тегам