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

发布于 2024-08-04 03:42:07 字数 474 浏览 9 评论 0 原文

如果您有一个在设置时需要修改的属性,是否有一种巧妙的方法可以自己编写访问器并直接修改 $self 的内容,就像完成的那样在这个例子中?

package Foo;
use Moose;

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

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

我考虑过触发,但似乎需要相同的方法。

直接使用 $self 中的哈希引用被认为是 Moose,还是我担心的是一个不存在的问题?

If you have an attribute that needs to be modified any time it is set, is there a slick way of doing this short of writing the accessor yourself and mucking around directly with the content of $self, as done in this example?

package Foo;
use Moose;

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

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

I considered trigger, but it seemed to require the same approach.

Is working directly with the hash reference in $self considered bad practice in Moose, or am I worrying about a non-issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

☆獨立☆ 2024-08-11 03:42:07

您可以使用方法修饰符“around”。像这样的事情:

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

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

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

另外,请不要认为我提供的选项一定是正确的。在大多数情况下,使用子类型和强制转换将是正确的解决方案 - 如果您根据可以在整个应用程序中重用的类型来考虑您的参数,将导致更好的设计,而不是可以进行的任意修改使用“周围”完成。请参阅@daotoad 的回答。

You can use the method modifier 'around'. Something like this:

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

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

And yes, working directly with the hash values is considered bad practice.

Also, please don't assume that the option I presented is necessarily the right one. Using subtypes and coercion is going to be the right solution most of the time - if you think about your parameter in terms of a type that can possibly be reused throughout your application will lead to much better design that the kind of arbitrary modifications that can be done using 'around'. See answer from @daotoad.

云朵有点甜 2024-08-11 03:42:07

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

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

这个弱点可能是好的,也可能使这种方法无法使用。在适当的情况下,这甚至可能是一种优势。

I'm not sure what kind of modification you need, but you might be able to achieve what you need by using type coercion:

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,
);

If you use this approach, not all values will be modified. Anything that passes validation as a ModStr will be used directly:

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

This weakness could be OK or it could make this approach unusable. In the right circumstances, it might even be an advantage.

陈独秀 2024-08-11 03:42:07

我认为在 trigger< 中使用哈希引用很好/a> 像这样:

package Foo;
use Moose;

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

bar 参数与构造函数一起传递时,触发器也会触发。如果您定义自己的 set_bar 方法或使用方法修饰符,则不会发生这种情况。

回复:哈希引用 - 一般来说,我认为最好坚持使用属性设置器/获取器,除非(如上面的触发器)没有简单的替代方案。

顺便说一句,您可能会发现这篇最近关于触发器的帖子,作者:没什么有趣的

I think using the hash reference is fine within a trigger like this:

package Foo;
use Moose;

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

The trigger also fires when bar arg passed with the constructor. This won't happen if you define your own set_bar method or with a method modifier.

re: hash reference - Generally I think its best to stick with the attribute setters/getters unless (like with above trigger) there is no easy alternative.

BTW you may find this recent post about triggers by nothingmuch interesting.

一城柳絮吹成雪 2024-08-11 03:42:07

如果直接处理哈希引起您的担忧,您可以指定一个备用编写器,然后在您自己适当命名的“公共”编写器中使用它。

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)

If dealing with the hash directly is causing you concern, you could specify an alternate writer and then use that from within your own appropriately named 'public' writer.

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);
}

This, or triggers, would strike me as being a good approach depending on when and how you need to be manipulating the arguments.

(disclaimer: untested code written from memory, browsing SO on a netbook with flaky edge access)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文