#perl
#perl
Вопрос:
Приведите приведенный ниже код, похоже, что порядок, в котором вы устанавливаете объекты, имеет значение. Приведенный ниже код выведет один и тот же список для обоих объектов, хотя я ожидал бы другого списка для каждого, потому что list — это атрибут экземпляра, который создается во время сборки.
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();
Текущий вывод:
[
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
[
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
Ожидаемый результат:
[
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
[
[0] "foo",
[1] "bar",
[2] "baz"
]
Ответ №1:
Поскольку вы изменяете рассматриваемый массив, вам не нужна ссылка на массив, который вы используете по умолчанию @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();
Пока я этим занимаюсь, использование BUILD для изменения атрибута возможно, но не обязательно является лучшим. Вы можете использовать что-то вроде отложенного атрибута с методом 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();