26

可能重复:
在 Perl 中制作数据结构的深层副本的最佳方法是什么?

在我开始自己编写代码并重新发明轮子之前,如何在不复制 hashref 的情况下复制散列散列?

我正在通过Config::General读取散列的散列。即数据结构为:

my %config = ( group => { item1 => { foo => 'value',
                                     bar => 'value',
                                   },
                          item2 => { foo => 'value',
                                     bar => 'value',
                                   },
                          item3 => { foo => 'value',
                                     bar => 'value',
                                   },
                        },
             );

然后我通过取消引用从配置中提取我的组,并在重写配置文件之前在运行时更改内容:

my %group = %{$config{'group'}};

问题是我需要检查是否进行了更改并对系统的文件结构进行相关更改。我不能通过检查来做到这一点:

if ($group{'item1'}{'foo'} ne $config{'group'}{'item1'}{'foo'}) {
    ### Stuff!
}

as$group{'item1'}$config{'group'}{'item1'}都是完全相同的 hashref。

现在虽然简单地重新解析配置文件并在保存到磁盘之前将磁盘中的解析副本与编辑版本进行比较应该是微不足道的,但我确信有一种方法可以对复杂数据结构进行嵌套取消引用,复制哈希引用的内容,而不是简单地复制引用本身。对 CPAN 的粗略检查并没有发现任何问题。我错过了什么?

基准

得到了我的答案:

#!/usr/bin/perl

use Benchmark qw(:all) ;
use Storable qw(dclone);
use Clone qw(clone);

my %config = ( group => { item1 => { foo => 'value',
                                     bar => 'value',
                                   },
                          item2 => { foo => 'value',
                                     bar => 'value',
                                   },
                          item3 => { foo => 'value',
                                     bar => 'value',
                                   },
                        },
             );

my $ref = $config{'group'};

timethese(100000, {
  'Clone' => sub { my %group = %{ clone $ref }},
  'Storable' => sub {  my %group = %{ dclone $ref }},
});

结果是:

基准测试:对 Clone、Storable 的 100000 次迭代计时...
   克隆:2 挂钟秒(2.26 usr + 0.01 sys = 2.27 CPU)@ 44052.86/s (n=100000)
可存储:5 挂钟秒(4.71 usr + 0.02 sys = 4.73 CPU)@ 21141.65/s (n=100000)
4

4 回答 4

37
use Storable qw(dclone);
$group2 = dclone(\%group);
于 2009-10-09T22:18:29.257 回答
30

从 Storable::dclone 文档中我找到了Clone

my $copy = clone (\@array);

# or

my %copy = %{ clone (\%hash) };

不需要灵活性,并声称比Storable::dclone更快。

于 2009-10-09T22:23:54.347 回答
7

深度数据结构101:

  • 使用Storable制作结构的dclone深层副本,并对freeze它们thaw进行序列化/反序列化以进行存储(例如在数据库或 http cookie 中(但您应该加密发送给用户的任何内容,以使其更难篡改) )。
  • 使用Data::Compare(或单元测试中的Test::DeepTest::Differences)来比较两个深层数据结构。
  • 在调试中使用Data::DumperData::Dump来查看对象的外观。但不要将其用作篡改另一个对象内部结构的许可证;使用 API。:)
于 2009-10-09T22:33:19.723 回答
-3

始终可以通过 Storable 或 Data::Dumper 存储散列,并将存储的值重新分配到新的散列中。这应该得到一个完整的副本,而不维护引用的链接。

use Storable;
my $serialized = freeze \%config;
my %newconfig = %{ thaw($serialized) };
于 2009-10-09T22:19:01.953 回答