zou*_*oul 7 perl moose immutability
这看起来似乎是一个明显无望的案例,但是有一个技巧可以在Perl中创建不可变对象的循环图吗?像这样的东西:
package Node;
use Moose;
has [qw/parent child/] => (is => 'ro', isa => 'Node');
package main;
my $a = Node->new;
my $b = Node->new(parent => $a);
Run Code Online (Sandbox Code Playgroud)
现在,如果我想$a->child指出$b,我该怎么办?
您可以使用延迟初始化来玩游戏:
package Node;
use Moose;
has parent => (
is => 'ro',
isa => 'Node',
lazy => 1,
init_arg => undef,
builder => '_build_parent',
);
has _parent => (
is => 'ro',
init_arg => 'parent',
);
has child => (
is => 'ro',
isa => 'Node',
lazy => 1,
init_arg => undef,
builder => '_build_child',
);
has _child => (
is => 'ro',
init_arg => 'child',
predicate => undef,
);
has name => is => 'ro', isa => 'Str';
Run Code Online (Sandbox Code Playgroud)
动态生成构建器和谓词:
BEGIN {
for (qw/ parent child /) {
no strict 'refs';
my $squirreled = "_" . $_;
*{"_build" . $squirreled} = sub {
my($self) = @_;
my $proto = $self->$squirreled;
ref $proto eq "REF" ? $$proto : $proto;
};
*{"has" . $squirreled} = sub {
my($self) = @_;
defined $self->$squirreled;
};
}
}
Run Code Online (Sandbox Code Playgroud)
这允许
my $a = Node->new(parent => \my $b, name => "A");
$b = Node->new(child => $a, name => "B");
for ($a, $b) {
print $_->name, ":\n";
if ($_->has_parent) {
print " - parent: ", $_->parent->name, "\n";
}
elsif ($_->has_child) {
print " - child: ", $_->child->name, "\n";
}
}
Run Code Online (Sandbox Code Playgroud)
它的输出是
A:
- parent: B
B:
- child: A
Run Code Online (Sandbox Code Playgroud)
该代码可以用更优雅η转换,但驼鹿不会通过参数生成器方法.
我必须去看看真正的不可变语言是如何做这样的事情的,我认为以下可能是一个合理的尝试。
use 5.10.0;
{
package Node;
use Moose;
has [qw(parent child)] => ( isa => 'Node', is => 'ro' );
sub BUILD {
my ( $self, $p ) = @_;
return unless exists $p->{_child};
my $child = Node->new( parent => $self, %{ delete $p->{_child} }, );
$self->meta->get_attribute('child')->set_value( $self, $child );
}
}
say Node->new( _child => {} )->dump
Run Code Online (Sandbox Code Playgroud)
基本上,您不必尝试单独构建对象,而是让父级根据传入的参数自动激活子级。其输出是,我相信这是您想要的结构。
$VAR1 = bless( {
'child' => bless( {
'parent' => $VAR1
}, 'Node' )
}, 'Node' );
Run Code Online (Sandbox Code Playgroud)