gpt4 book ai didi

perl - 由内而外的 Perl 类的深度克隆 - 如何使用复制对象的方法?

转载 作者:行者123 更新时间:2023-12-03 19:11:12 25 4
gpt4 key购买 nike

我使用 Class::Std 将 3 个类声明为由内而外的 Perl 类.在这 3 个中的一个中,有一个哈希引用存储在 $basket{ident $self} 中。看起来像这样(Data::Dumper 的输出):

$VAR1 = {
'auto' => {
'items' => {
'abc' => bless( do{\(my $o = undef)}, 'Item' )
},
'obj' => bless( do{\(my $o = undef)}, 'Category' )
}
};

我需要获取这个散列引用并再次在其中创建所有内容(深度克隆)。我尝试使用 dclone来自 Storable像这样:
my $new_basket = dclone $basket{ident $self};

当我打印散列时,我得到不同的内存地址:
print $new_basket, "\n";
print $basket{ident $self}, "\n";
print $new_basket->{auto}->{items}, "\n";
print $basket{ident $self}{auto}->{items}, "\n";
print $new_basket->{auto}->{items}->{abc}, "\n";
print $basket{ident $self}{auto}->{items}->{abc}, "\n";

这将输出:
HASH(0x55d325306a20)
HASH(0x55d325245298)
HASH(0x55d323b35ca8)
HASH(0x55d3243dd968)
Item=SCALAR(0x55d323b45190)
Item=SCALAR(0x55d325306588)

当我不使用时 dclone并使用 my $new_basket = $basket{ident $self}相反,我得到了相同的内存地址。当我使用 my $new_basket = { %{ $basket{ident $self} } } ,我只在第一层得到不同的地址,应该是浅拷贝。所有这一切似乎都很好并且在意料之中。

所以,在我看来 dclone实际上深度复制了所有内容,因为地址不同。但是当我尝试在 Item 中使用方法时像这样:
print $new_basket->{auto}->{items}->{abc}->get_added_on();
print $basket{ident $self}{auto}->{items}->{abc}->get_added_on();

我得到:
Use of uninitialized value in print at lib/Basket.pm line 231.
2020-05-30

很明显 dclone与我天真地认为的不同。

我应该如何深度复制整个结构? 我很感激一些帮助或引用一些文章/文档,在那里我可以阅读这里发生的事情。

一种解决方案是使用构造函数再次创建整个结构,但我想我会节省一些空间并使用 dclone。结果显然不是很好。

编辑:我被要求提供一个最小的可运行演示,这里是:
#!/usr/bin/env perl

use strict;
use warnings;

{
package A;
use Class::Std;
use Data::Dumper;
use Storable qw(dclone);

my %basket :ATTR;

sub BUILD {
my ($self, $ident, $args_ref) = @_;
$basket{$ident}->{auto} = {};

my $c = C->new({ date => q{2020-05-30} });

$basket{$ident}->{auto}->{items}->{abc} = $c;

return;
}

sub deep_clone {
my $self = shift;

print Dumper $basket{ident $self};
# the next line prints "2020-05-30" as expected
print $basket{ident $self}->{auto}->{items}->{abc}->get_added_on();
my $new_basket = dclone $basket{ident $self};
# "Use of uninitialized value in print at ./deep-clone.pl line 35."
print $new_basket->{auto}->{items}->{abc}->get_added_on();
}
}

{
package C;
use Class::Std;

my %added_on :ATTR( :get<added_on> );

sub BUILD {
my ($self, $ident, $args_ref) = @_;

$added_on{$ident} = $args_ref->{date};

return;
}
}

####

my $a = A->new();
$a->deep_clone();

最佳答案

新创建的“C”对象从未添加到 %added_on .

您的类必须为 Storable 提供自定义处理程序来处理它们。

添加到“A”:

sub STORABLE_freeze {
my ($self, $cloning) = @_;
my $ident = ident($self);
return "", {
basket => $basket{$ident},
# Other attributes...
};
}

sub STORABLE_thaw {
my ($self, $cloning, $serialized, $inner) = @_;
my $ident = ident($self);
$basket{$ident} = $inner->{basket};
# Other attributes...
}

添加到“C”:

sub STORABLE_freeze {
my ($self, $cloning) = @_;
my $ident = ident($self);
return "", {
added_on => $added_on{$ident},
# Other attributes...
};
}

sub STORABLE_thaw {
my ($self, $cloning, $serialized, $inner) = @_;
my $ident = ident($self);
$added_on{$ident} = $inner->{added_on};
# Other attributes...
}

那么你可以使用 freeze/ thaw/ dclone没有问题。

sub deep_clone {
my $self = shift;

#print Dumper $basket{ident $self};
CORE::say $basket{ ident $self }{auto}{items}{abc}->get_added_on();

my $clone = dclone($self);

#print Dumper $basket{ident $self};
CORE::say $basket{ ident $clone }{auto}{items}{abc}->get_added_on();
}

关于perl - 由内而外的 Perl 类的深度克隆 - 如何使用复制对象的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62102193/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com