在Moose中,如何在设置属性时修改属性?

FMc*_*FMc 19 perl moose

如果你有一个属性需要在它设置的任何时候进行修改,那么是否有一种简单的方法可以自己编写访问器并直接使用内容$self,如本例中所做的那样?

package Foo;
use Moose;

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

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

我考虑过trigger,但似乎需要采用相同的方法.

$selfMoose中被认为是不好的做法直接使用哈希引用,还是我担心没有问题?

aaa*_*210 10

您可以使用方法修饰符'around'.像这样的东西:

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

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

是的,直接使用哈希值被认为是不好的做法.

另外,请不要认为我提出的选项必然是正确的.在大多数情况下使用子类型和强制将是正确的解决方案 - 如果您根据可能在整个应用程序中重用的类型来考虑您的参数将导致更好的设计,即可以进行任意修改使用'around'完成.请参阅@daotoad的回答.


dao*_*oad 8

我不确定你需要什么样的修改,但是你可以通过使用类型强制来实现你所需要的:

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,
);
Run Code Online (Sandbox Code Playgroud)

如果使用此方法,则不会修改所有值.任何将验证作为ModStr传递的内容都将直接使用:

my $f = Foo->new();
$f->bar('modified: bar');  # Set without modification
Run Code Online (Sandbox Code Playgroud)

这种弱点可能没问题,也可能使这种方法无法使用.在适当的情况下,它甚至可能是一个优势.


dra*_*tun 6

我认为在这样的触发器中使用哈希引用很好:

package Foo;
use Moose;

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

触发时,也触发酒吧 ARG与构造函数.如果您定义自己的set_bar方法或使用方法修饰符,则不会发生这种情况.

re:哈希引用 - 一般来说我认为最好坚持使用属性setter/getters,除非(与上面的触发器一样)没有简单的替代方案.

顺便说一句,你可能会发现这篇关于触发器最新文章并不是很有趣.