gpt4 book ai didi

perl - 惰性属性强制

转载 作者:行者123 更新时间:2023-12-03 17:56:34 24 4
gpt4 key购买 nike

Moose , 你可以有 lazy builders在属性上,如果尚未填充该属性,则在首次访问该属性时调用该构建器。您可以使用 coerce 对属性进行类型强制。 ,但是只要设置了属性,就会应用它,即使在对象初始化时也是如此。

我正在寻找一种方法来实现懒惰强制 ,其中一个属性可能最初被填充,但仅在第一次访问时才被强制。当强制很昂贵时,这一点很重要。

在以下示例中,我使用联合类型和方法修饰符来执行此操作:

package My::Foo;
use Moose;
has x => (
is => 'rw',
isa => 'ArrayRef | Int',
required => 1
);

around "x" => sub {
my $orig = shift;
my $self = shift;
my $val = $self->$orig(@_);
unless(ref($val)) {
# Do the cocerion
$val = [ map { 1 } 1..$val ];
sleep(1); # in my case this is expensive
}
return $val;
};
1;

my $foo = My::Foo->new( x => 4 );
is_deeply $foo->x, [ 1, 1, 1, 1 ], "x converted from int to array at call time";

但是,这样做存在一些问题:
  • 我不喜欢联合类型 + 方法修饰符的方法。它违背了对 use coercion instead of unions 的“最佳实践”建议。 .它不是声明性的。
  • 我需要在许多类中使用许多属性来做到这一点。因此需要某种形式的 DRY。这可能是元属性角色,类型强制,你有什么。

  • 更新:
    我关注了 ikegami's建议将昂贵的类型强制封装在对象内部并为此对象提供外部强制:
    package My::ArrayFromInt;
    use Moose;
    use Moose::Util::TypeConstraints;
    subtype 'My::ArrayFromInt::Inner',
    as 'ArrayRef[Int]';
    coerce 'My::ArrayFromInt::Inner',
    from 'Int',
    via { return [ (1) x $_ ] };
    has uncoerced => (is => 'rw', isa => 'Any', required => 1);
    has value => (
    is => 'rw',
    isa => 'My::ArrayFromInt::Inner',
    builder => '_buildValue',
    lazy => 1,
    coerce => 1
    );
    sub _buildValue {
    my ($self) = @_;
    return $self->uncoerced;
    }
    1;
    package My::Foo;
    use Moose;
    use Moose::Util::TypeConstraints;
    subtype 'My::ArrayFromInt::Lazy' => as class_type('My::ArrayFromInt');
    coerce 'My::ArrayFromInt::Lazy',
    from 'Int',
    via { My::ArrayFromInt->new( uncoerced => $_ ) };
    has x => (
    is => 'rw',
    isa => 'My::ArrayFromInt::Lazy',
    required => 1,
    coerce => 1
    );
    1;

    如果 $foo->x->value叫做。但是,这并不能解决第 2 点,因为我需要创建 My::ArrayFromInt::Lazy我想转换的每个属性的子类型。我想避免调用 $foo->x->value如果可能的话。

    最佳答案

    如何按照所描述的方式使用 typedef,然后执行

    has _x => (
    is => 'ro',
    isa => 'Int|MyArrayOfInts',
    init_arg => 'x',
    required => 1,
    );

    has x => (
    is => 'ro',
    lazy => 1,
    isa => 'MyArrayOfInts',
    coerce => 1,
    default => sub { $_[0]->_x },
    );

    将其包装成某种辅助方法来创建沿线的对象对是有意义的
    has_lazily_coerced x => (
    is => 'ro',
    isa => 'TargetType',
    );

    这将自省(introspection) TargetType 以获取未强制影子属性的合法类型列表并为您生成一对属性。

    关于perl - 惰性属性强制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10539765/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com