В 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, или я беспокоюсь о не-проблеме
Ответы
Ответ 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 на нетбуке с закрытым доступом к краю)