10

我正在寻找一个受祝福的对象的深层(在这一点上,浅层可能就足够了)副本。

Foo 类

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 或其他非核心模块/包,所以在回复时请记住这一点。 加粗,使其更加突出:)

4

5 回答 5

15

复制应该是 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;
}
于 2013-05-09T15:13:43.557 回答
10

use Storable 'dclone';?

$ corelist Storable

Storable was first released with perl v5.7.3

另外,您可以摆弄 Storable 挂钩来断言对复制对象的更好控制(不是我已经做到了,但这就是文档所声称的)。

于 2013-05-09T16:02:20.353 回答
4

my $copy = bless { %$self }, ref $self;@chorba 的回答是不够的。它只会克隆第一层。存储在其中的任何引用$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 复制到您的项目中即可。

另一种选择是@Zaid 提到的Storable::dclone,它已经成为核心很长时间了。

无论您使用什么,在您的类上提供一个克隆方法都是正确的做法,即使它只是 Clone 或 Storable::dclone 的包装器。这将使您的对象的用户免受您的对象如何被克隆的详细信息。

于 2013-05-09T18:55:39.890 回答
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
    );
}
于 2013-05-09T17:30:16.053 回答
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";
于 2014-01-28T09:03:33.913 回答