如何有效地对 Moose 属性应用正则表达式替换?

How to efficiently apply a regex substitution on a Moose attribute?

我有一个

package Test;
use Moose;
has 'attr' => ( is => 'rw', isa => 'Str' );

在一个方法中,我想在属性上应用 s/pattern/string/g。由于 Moose 中记录的原因(基本上是为了正确支持多态性)我不想直接访问 $self->{attr},所以一个简单的:

$self->{attr} =~ s/pattern/string/g;

不是一个选项。我怎样才能使用 Moose 快速高效地完成此操作,并且代码少而清晰?

我想到的选项是:

1) 使用临时变量,通常的getter/setter方法:

my $dummy = $self->attr;
$dummy =~ s/pattern/string/g;
$self->attr($dummy);

2) 使用左侧的 attr getter/setter:

$self->attr($dummy) =~ s/pattern/string/g;

但这显然会引发错误

Can't modify non-lvalue subroutine call at Test.pm line 58, line 29

有没有办法像 lvalue subs 一样使用 Moose 访问器?

3) 使用 String traits

重新定义属性:

has 'attr' => ( is => 'rw', isa => 'Str', traits  => ['String'],
                handles => { replace_attr => 'replace'}  );

然后在方法中使用:

$self->replace_attr('pattern', 'string');

但是文档明确指出,无法指定 /g 标志。

是否有开箱即用的优雅、简单、有点高效的方法?

我过去使用过这种方法,我认为就效率和清洁度而言,它似乎适合我的一般用途。它也适用于 /g 修饰符。

$self->attr( $self->attr =~ s/pattern/string/gr );

我怀疑在幕后这与您使用临时变量的第一个示例相同,它只是对我们隐藏了。

请注意,要使用 /r 修饰符,returns 替换结果而不修改原始值,需要 Perl 5.14+。

我的选择 (2) 和 this question provide the idea to use MooseX::LvalueAttributes:

package Test;
use Moose;
use MooseX::LvalueAttribute 'lvalue';
has 'attr' => ( is => 'rw', isa => 'Str', traits => [lvalue] );

这允许使用简单的语法:

$self->attr($dummy) =~ s/pattern/string/g;

这在内部使用了 Variable::Magic and the perlsub lvalue 功能,因此这种方法存在性能开销,它会影响对 'traited' 属性的每次访问,而不仅仅是用作左侧的那些。感谢 LeoNerd 和 ikegami 对我之前陈述的更正意见。

因此,经模块文档确认,Moose 的类型检查仍然有效,并且触发了触发器。