Moo对象扩展顺序

Spa*_*eyG 4 perl

给下面的代码,似乎您实例化对象的顺序很重要。当我希望每个对象都使用不同的列表时,以下代码将为两个对象打印相同的列表,因为列表是在构建时创建的实例属性。

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)

Joe*_*ger 7

由于您要对有问题的数组进行突变,因此您不希望引用用作默认数组的数组,因此\@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)