给下面的代码,似乎您实例化对象的顺序很重要。当我希望每个对象都使用不同的列表时,以下代码将为两个对象打印相同的列表,因为列表是在构建时创建的实例属性。
package t;
use Moo;
use Types::Standard qw(ArrayRef);
my @list = qw/foo bar baz/;
has list => (
is => 'rw',
isa => ArrayRef,
default => sub {\@list}
);
1;
---
package u;
use Moo;
use Types::Standard qw(ArrayRef);
extends 't';
sub BUILD {
my ($self) = @_;
push @{$self->list()}, qw/apple banana/;
return $self;
}
1;
---
#!perl
use Data::Printer;
use t;
use u;
my $u = u->new();
p $u->list();
my $t = t->new();
p $t->list();
Run Code Online (Sandbox Code Playgroud)
电流输出:
\ [
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
\ [
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
Run Code Online (Sandbox Code Playgroud)
预期产量:
\ [
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
\ [
[0] "foo",
[1] "bar",
[2] "baz"
]
Run Code Online (Sandbox Code Playgroud)
由于您要对有问题的数组进行突变,因此您不希望引用用作默认数组的数组,因此\@list需要进行浅表复制[@list]。
package t;
use Moo;
use Types::Standard qw(ArrayRef);
my @list = qw/foo bar baz/;
has list => (
is => 'rw',
isa => ArrayRef,
builder =>
default => sub { [@list] }
);
package u;
use Moo;
use Types::Standard qw(ArrayRef);
extends 't';
sub BUILD {
my ($self) = @_;
push @{$self->list()}, qw/apple banana/;
return $self;
}
package main;
use Data::Printer;
my $u = u->new();
p $u->list();
my $t = t->new();
p $t->list();
Run Code Online (Sandbox Code Playgroud)
我正在使用BUILD修改属性是可能的,但不一定是最好的。您可以将类似lazy属性的内容与builder方法一起使用,然后在子类ala中重载该方法
package t;
use Moo;
use Types::Standard qw(ArrayRef);
my @list = qw/foo bar baz/;
has list => (
is => 'rw',
isa => ArrayRef,
builder => '_build_list',
lazy => 1,
);
sub _build_list {
my $self = shift;
return [@list];
}
package u;
use Moo;
extends 't';
sub _build_list {
my $self = shift;
my $list = $self->SUPER::_build_list();
push @$list, qw/apple banana/;
return $list;
}
package main;
use Data::Printer;
my $u = u->new();
p $u->list();
my $t = t->new();
p $t->list();
Run Code Online (Sandbox Code Playgroud)