Подтвердить что ты не робот

В Moose, как мне изменить атрибут в любое время его установки?

Если у вас есть атрибут, который необходимо изменить в любое время, когда он установлен, есть ли пятно способ сделать это, не нажимая себе аксессуар, и прятаться напрямую с содержимым $self, как это сделано в этом примере

package Foo;
use Moose;

has 'bar' => (
    isa => 'Str',
    reader => 'get_bar',
);

sub set_bar {
    my ($self, $bar) = @_;
    $self->{bar} = "modified: $bar";
}

Я считал trigger, но, похоже, он требовал того же подхода.

Работает непосредственно с хеш-ссылкой в ​​ $self, считающейся плохой практикой в ​​Moose, или я беспокоюсь о не-проблеме

4b9b3361

Ответ 1

Я не уверен, какая модификация вам нужна, но вы можете добиться того, что вам нужно, используя принуждение типа:

package Foo;
use Moose;

use Moose::Util::TypeConstraints;

subtype 'ModStr' 
    => as 'Str'
    => where { /^modified: /};

coerce 'ModStr'
    => from 'Str'
    => via { "modified: $_" };

has 'bar' => ( 
    isa => 'ModStr', 
    is  => 'rw', 
    coerce => 1,
);

Если вы используете этот подход, не все значения будут изменены. Все, что проходит проверку как ModStr, будет использоваться напрямую:

my $f = Foo->new();
$f->bar('modified: bar');  # Set without modification

Эта слабость может быть в порядке, или это может сделать этот подход непригодным. При правильных обстоятельствах это может быть даже преимуществом.

Ответ 2

Вы можете использовать модификатор метода "around". Что-то вроде этого:

has 'bar' => (
    isa    => 'Str',
    reader => 'get_bar',
    writer => 'set_bar'
);

around 'set_bar' => sub {
    my ($next, $self, $bar) = @_;
    $self->$next( "Modified: $bar" );
};

И да, работа непосредственно с хэш-значениями считается плохой практикой.

Кроме того, пожалуйста, не предполагайте, что представленная мной опция обязательно является правильной. Использование подтипов и принуждения будет правильным решением в большинстве случаев - если вы подумали о своем параметре с точки зрения типа, который может быть повторно использован во всем приложении, это приведет к значительно лучшему дизайну, чтобы вид произвольных модификаций, которые могут быть сделано с использованием "вокруг". См. Ответ от @daotoad.

Ответ 3

Я думаю, что использование хеш-ссылки в пределах trigger выглядит следующим образом:

package Foo;
use Moose;

has 'bar' => ( 
    isa => 'Str', 
    is  => 'rw', 
    trigger => sub { $_[0]->{bar} = "modified: $_[1]" },
);

Триггер также срабатывает, когда bar arg передается вместе с конструктором. Это не произойдет, если вы определите свой собственный метод set_bar или модификатор метода.

re: хеш-ссылка - Как правило, я считаю, что лучше всего использовать атрибут-сеттеры/геттеры, если (например, с помощью вышеприведенного триггера) нет простой альтернативы.

Кстати, вы можете найти это последнее сообщение о триггерах nothingmuch интересный.

Ответ 4

Если обращение с хешем напрямую вызывает у вас беспокойство, вы можете указать альтернативного автора, а затем использовать его из собственного собственного "публичного" автора.

package Foo;
use Moose;

has 'bar' => (
   isa => 'Str',
   reader => 'get_bar',
   writer => '_set_bar',
);

sub set_bar {
   my $self = shift;
   my @args = @_;
   # play with args;
   return $self->_set_bar(@args);
}

Это, или триггеры, поразило бы меня как хороший подход в зависимости от того, когда и как вам нужно манипулировать аргументами.

(отказ от ответственности: непроверенный код, записанный из памяти, просмотр SO на нетбуке с закрытым доступом к краю)