我希望做一个深刻的(在这一点上,浅浅可能就足够了)一个受祝福的物体的副本。
Foo Class
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或其他非核心模块/软件包,因此请在回复时牢记这一点。 Bolded so stand stand更多:)
答案 0 :(得分:11)
复制应该是API的一部分。模块的用户永远不会知道在创建新对象时需要执行哪些特殊操作(考虑在包中的my
哈希中注册每个对象)。
因此,请为您的对象提供clone
方法。在它里面,你可以使用你喜欢的任何肮脏技巧:
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;
}
答案 1 :(得分:9)
$ corelist Storable
Storable was first released with perl v5.7.3
另外,你可以摆弄Storable钩子,以便更好地控制复制你的对象(不是我已经完成了,但这就是文档声称的内容)。
答案 2 :(得分:4)
my $copy = bless { %$self }, ref $self;
是不够的。它只会克隆第一层。存储在$self
中的任何引用都不会被克隆。这样做的后果是......
$obj->{ponies} = [qw(Dash Sparkle Jack)];
$clone = $obj->clone;
push @{$clone->{ponies}}, "Pinkie";
print join ", ", @{$obj->{ponies}}; # Dash Sparkle Jack Pinkie
您现在可能没有任何参考,但您可能会稍后。或者别人会把一个粘在你的物体上。或者他们将继承并添加一个。
您可以编写深度克隆例程,但这并不简单。我强烈建议使用Clone。它没有依赖关系,因此您只需将Clone.pm复制到项目中即可。
另一个选择是Storable::dclone,由@Zaid提及,长期以来一直处于核心地位。
无论你使用什么,在你的类上提供克隆方法是正确的,即使它只是Clone或Storable :: dclone的包装器。这将保护对象的用户免受克隆对象的详细信息的影响。
答案 3 :(得分:3)
调用程序没有好办法知道"复制对象"需要,所以一个对象应该知道如何复制自己。 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
);
}
答案 4 :(得分:0)
对不起,我没注意到这句话:
* 我正在尝试避免使用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";