【问题标题】:Force coercion in Moose在 Moose 中强制强制
【发布时间】:2015-07-15 15:42:53
【问题描述】:

我想在每次设置时修改属性的值,无论它是在构造函数中完成还是由“编写器”完成(在这种情况下我不使用“构建器”或“默认”)。基本上属性(不需要'Str'类型)被传递给构造函数,在某些情况下我想在此之后修改它的值,但在每种情况下我都想对它做一些正则表达式(例如)。

我的第一种方法是使用 BUILDARGS 和 around 方法,两者都将使用相同的正则表达式函数,但后来我想知道强制。唯一的问题是我不知道如何创建一个无论如何都会强制强制的子类型/类型定义。

例如:

package Foo;
use Moose::Util::TypeConstraints;

subtype 'Foo::bar' => as 'Str';
coerce 'Foo::bar'
    => from 'Str'
        => via {
            $_ =~ s/some_stuff//g;
            $_ =~ s/other_stuff//g;
            $_ =~ s/some_other_stuff//g;
        };

has 'bar' => (isa => 'Foo:bar', coerce => 1);

我不想用'where'子句定义子类型/类型

subtype 'Foo::bar' => as 'Str' => where {$_ !~ /some_stuff/ && $_ !~ /other_stuff/ && ... };

因为这对我来说似乎很乏味。

编辑:我正在寻找一个全面的解决方案,我不仅可以使用“Str”类型属性,还可以使用“ArrayRef”、“HashRef”等。

【问题讨论】:

  • 你是说强制并不总是发生吗?什么情况下不强制取值?
  • @ikegami Foo->new( bar => 'Some string' ) 不会发生强制,因为传递的值已经是一个字符串。 “强制让你告诉 Moose 自动将一种类型转换为另一种”,输入和输出类型都是字符串。我不坚持使用这种方法,只是寻找最佳选择。
  • 所以你是说强制永远不会发生?请说明你的问题是什么!!!至少提供一个演示!
  • 你说得对,我不够清楚。强制有效,但它不会进入“via”块,因为传递的值和子类型都是字符串,并且子类型定义中没有“where”子句可以强制强制进入“via”块。

标签: perl moose coercion


【解决方案1】:

听起来你想要trigger

package Foo;
use Moose;

has 'bar' => (
    is      => 'rw',
    isa     => 'Str',
    trigger => sub {
        my ( $self, $value, $old_value ) = @_;
say 'in trigger';
        # prevent infinite loop
        return if $old_value && $old_value eq $value;

        my $original_value = $value;
        $value =~ s/some_stuff//g;
        $value =~ s/other_stuff//g;
        $value =~ s/some_other_stuff//g;

        # prevent infinite loop
        return if $value eq $original_value;

say '... setting new value';
        $self->bar($value);
    },
);

package main;

my $foo = Foo->new( bar => 'foo some_stuff and other_stuff and some_more_stuff' );
say $foo->bar;

我想在每次设置时修改属性的值,不管 如果它是在构造函数中或由“作家”完成的(我不使用 'builder' 或 'default' 在这种情况下)

这正是触发器的作用。医生几乎一字不差地说出了你的要求:

注意:触发器只会在您分配给属性时触发,无论是在构造函数中,还是使用编写器。默认值和构建值不会导致触发器被触发。

编辑: inifite 循环检测中存在错误。它现在可以工作并将在第二次调用时停止。我留下调试输出来演示。

in trigger
... setting new value
in trigger
foo  and  and some_more_stuff

【讨论】:

  • 你会得到一个无限递归。触发属性设置后触发,因为您在子中再次设置“栏”,触发将陷入无限循环。如果您在触发器子中以这种方式设置属性$self->{bar} = 'modified_value',上面的示例将起作用,但从我读到的处理 $self 作为哈希引用是不好的做法。
  • 我的答案的第一个版本没有无限循环。事实上,它没有任何改变,因为我有一个错误。我已经用一个可以在不创建无限循环的情况下做你想做的事情的版本更新了答案。
  • 您的问题是针对Str 的,并且您明确表示您不想在问题的最后部分实际验证字符串的类型。检查字符串是否需要那些替换正是强制所基于的类型。对于不是字符串的事情,我同意强制更有意义。但是您询问了一个非常具体的案例,这就是该具体问题的答案。要么接受,要么离开它。 :)
  • 我正在寻找更全面的解决方案。这些变通办法适用于“Str”类型的值,但不适用于更复杂的结构。从我读过的内容来看,强制将是最好的解决方案,但我不知道如何实现它。
  • 基本上我的问题正是第一句话所说的。下面的代码只是一个例子,我没有在描述中提到任何关于字符串类型的内容(我将编辑我的问题,所以没有人会对此感到困惑)。我正在寻找一个全面的解决方案,我不想使用解决方法,但如果没有更好的解决方案,我保证我会将您的答案标记为最佳解决方案;)
猜你喜欢
  • 1970-01-01
  • 2011-07-04
  • 2014-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多