Perl:如何深度复制受祝福的对象?
我希望做一个深(在这一点上,浅可能足够)的祝福对象副本 福类Perl:如何深度复制受祝福的对象?,perl,oop,deep-copy,bless,Perl,Oop,Deep Copy,Bless,我希望做一个深(在这一点上,浅可能足够)的祝福对象副本 福类 package Foo; our $FOO = new Foo; # initial run sub new { my $class = shift; my $self = {}; bless $self, $class; return $self; } 主程序 use Foo; my $copy = $Foo::FOO; # instead of creating a ref, wa
package Foo;
our $FOO = new Foo; # initial run
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
主程序
use Foo;
my $copy = $Foo::FOO; # instead of creating a ref, want to deep copy here
$copy->{bar} = 'bar';
bar
同时出现在$Foo::Foo
和$copy
中。我意识到我可以通过将对象设置为$copy={%{$Foo::Foo}}
来创建对象的副本,但这样它就不再受祝福了;此外,这只适用于简单的数据结构(目前不是问题)。只有这样才能复制,然后在之后祝福(例如$copy=bless{%{$Foo::Foo}},q{Foo};
)
我试图避免使用Moose、Clone或其他非核心模块/软件包,因此在回复时请记住这一点。加粗以使其更加突出:)复制应该是API的一部分。模块的用户永远不会知道创建新对象时需要执行哪些特殊操作(请考虑在包中的
my
散列中注册每个对象)
因此,为您的对象提供一种克隆方法。在它里面,你可以使用任何你喜欢的肮脏把戏:
sub clone {
my $self = shift;
my $copy = bless { %$self }, ref $self;
$register{$copy} = localtime; # Or whatever else you need to do with a new object.
# ...
return $copy;
}
?
此外,您还可以摆弄可存储钩子来对复制对象进行更精细的控制(虽然我没有这么做,但文档声称这是正确的)。调用程序无法知道“复制对象”需要什么,因此对象应该知道如何复制自己。Perl的OO在这里没有为您提供任何帮助,但传统的做法是:
package Car;
sub clone {
my ($self) = @_;
return $self->new(
( map { $_ => $self->$_() } qw/make model/ ), # built-in types
engine => $self->engine->clone(), # copying an object
);
}
my$copy=bless{%$self},ref$self@chorba的答案中的code>是不够的。它将只克隆第一层。将不会克隆存储在$self
中的任何引用。其后果是
$obj->{ponies} = [qw(Dash Sparkle Jack)];
$clone = $obj->clone;
push @{$clone->{ponies}}, "Pinkie";
print join ", ", @{$obj->{ponies}}; # Dash Sparkle Jack Pinkie
您现在可能没有任何参考资料,但以后可能会有。否则别人会把一个插进你的物体里。或者他们将子类化并添加一个
您可以编写一个深度克隆例程,但它并不简单。我强烈推荐使用。它没有依赖项,因此您可以简单地将Clone.pm复制到项目中
另一种选择是@Zaid提到的,它在核心中已经存在很长时间了
无论您使用什么,在类上提供clone方法都是正确的做法,即使它只是clone或Storable::dclone的包装器。这将使您的对象的用户不知道您的对象是如何克隆的。对不起,我注意不到这句话:
*我试图避免使用Moose、Clone或其他非核心模块/软件包,因此在回复时请记住这一点。加粗,使其更加突出:)*
所以这个答案不能被接受
#!/usr/bin/env perl -w
use strict;
use warnings;
use Storable;
use Data::Dumper;
my $src = {
foo => 0,
bar => [0,1]
};
$src -> {baz} = $src;
my $dst = Storable::dclone($src);
print '$src is : '.Dumper($src)."\n";
print '$dst is : '.Dumper($dst)."\n";
我想这可能是一条路。这将是我的下一步,我希望Perl有一些内置的东西可以做同样的事情,这样我就不必膨胀我的对象了,但是谢谢!另外my$dictionary=clone$book代码>读起来好多了。虽然这是公认的答案,但用户应该注意,这更多的是针对简单数据结构的浅层复制,而不会解决深度复制,甚至更高级的类结构。bless{%$self},ref$self
技术只会进行浅层复制。作为引用的$self
的属性将不会被克隆。例如,$obj->{ponies}=[qw(Dash Sparkle Jack)]$克隆=$obj->clone;push@{$clone->{ponies},“Pinkie”
将修改这两个对象。@Schwern:是的。我认为深度克隆是你必须使用的“肮脏伎俩”之一。@Schwern:这是一个很好的例子,说明它是如何进行浅层复制的。不过,在我几小时前的评论中(这里和问题评论),我提到了这是肤浅副本的公认答案。我可能最终会听取关于使用克隆
或可存储
的建议,但我觉得如果我开始使用模块,我可能会将其情绪化。公认的解决方案可能会改变:注意,它更适合于浅层复制简单数据结构,但不能解决深层复制,甚至更高级的类结构;这是我最初的问题。请记住,所选答案将来可能会更改。嗨,Rahil Wazir,这里有网站URL:,您可以找到:“Storable为您提供了一个dclone接口,它不会创建中间标量,而是将结构冻结在一些内部内存空间中,然后立即将其解冻。”,“Storable的核心是用C语言编写的,以保证速度。在操作perl内部时进行了额外的低级优化,以牺牲封装来提高速度。"; 我希望事情能对你有所帮助。你能把这部分编辑到你的答案中,而不是评论。我想说,有时候你希望两个克隆对象保持指向同一个引用对象。例如,如果您的Person
类具有一个employer
属性,该属性指向表示AcmeCorp组织的对象,则您可能不希望克隆Bob也克隆AcmeCorp。这些决定只能在一个类别一个类别的基础上做出,并且应该被彻底记录。@Tobynk是的,这就是为什么克隆是通过$obj->clone
而不是clone($obj)
完成的。对象可以最好地决定如何克隆它。clone
方法应该做什么定义不明确。这是一个肤浅的克隆人吗?深度克隆?“我认为合适”的克隆人?应该考虑并定义克隆方法的行为/接口。您可能需要几种克隆方法。
#!/usr/bin/env perl -w
use strict;
use warnings;
use Storable;
use Data::Dumper;
my $src = {
foo => 0,
bar => [0,1]
};
$src -> {baz} = $src;
my $dst = Storable::dclone($src);
print '$src is : '.Dumper($src)."\n";
print '$dst is : '.Dumper($dst)."\n";