这似乎是一个明显没有希望的情况,但是在 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);
现在,如果我想$a->child指向$b,我该怎么办?
这似乎是一个明显没有希望的情况,但是在 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);
现在,如果我想$a->child指向$b,我该怎么办?
我不得不去看看真正不可变的语言是如何做这样的事情的,我认为以下可能是一个合理的尝试。
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
基本上,不是尝试单独构建对象,而是让父级根据传入的参数自动激活子级。输出是,我相信你想要的结构。
$VAR1 = bless( {
'child' => bless( {
'parent' => $VAR1
}, 'Node' )
}, 'Node' );
我对 Moose 还是很陌生,但是触发器会起作用吗?
use Modern::Perl;
package Node;
use Moose;
has 'parent' => (
is => 'ro',
isa => 'Node',
trigger => sub{
my ($self, $parent) = @_;
$parent->{child} = $self unless defined $parent->child;
}
);
has 'child' => (
is => 'ro',
isa => 'Node',
trigger => sub{
my ($self, $child) = @_;
$child->{parent} = $self unless defined $child->parent;
}
);
package main;
my $p = Node->new;
my $c = Node->new(parent => $p);
say $p, ' == ', $c->parent;
say $c, ' == ', $p->child;