Perl 哈希数组正在添加来自其他数组的元素

Perl array of hash is adding elements from other arrays

我正在 perl 5.34.0 中创建哈希数组:

#!/usr/bin/env perl

use strict;
use warnings FATAL => 'all';
use autodie ':default';
use DDP;

my (@a1, @a2);
my %h = ('a' => 1);
push @a1, \%h; # make @a1 a hash of array with 'a' defined
$h{b} = 2; # define b within the hash, but don't write to @a1
push @a2, \%h; # push `a` and `b` onto @a2, but *not* @a1
p @a1; # DDP gives "p" which pretty-prints
p @a2;

这输出:

[
    [0] {
            a   1,
            b   2
        }
]
[
    [0] {
            a   1,
            b   2
        }
]

问题是 b 密钥出现在 @a1 中,但在将数据写入 @a1$h{b} 不存在。

我不想 b 出现在 @a1 中,也不应该。

如何修改 %h 使其不会神奇地出现在不同的数组中?

该代码将 reference 添加到现有(已命名)散列中,

push @a1, \%h;

所以当稍后查询时,您会看到当时在哈希中看到的任何内容。该数组仅携带一个带有数据地址的指针,也由散列引用;这是一个别名。因此,如果同时写入哈希,那么这就是您将通过 @a1.

看到的内容

再次添加,即使哈希值发生变化,您也只需添加相同的旧引用即可。

您想要的是制作数据副本并添加对其的引用 -- anonymous hash

push @a1, { %h };    # but may need deep copy instead

现在复制散列数据以填充由 {} 构造的匿名散列,我们有独立的数据,只能通过其在 @a1 中的引用写入它来更改。

但请注意,如果该散列中的值本身是引用,那么这些引用将被复制,我们会遇到同样的问题!在那种情况下,你需要一个深拷贝,最好用库来完成; Storable::dclone 不错

use Storable qw(dclone);

push @a1, dclone \%h;

现在所有实际数据都被复制了,用于(参考)@a1

上的独立数据副本

一个重要的异常,经常使用

foreach my $elem (@ary) { 
    my %h;
    # ... code that does its work and populates the hash ...
    push @res, \%h;
}

现在 this 没问题了,因为散列 %h 在每次迭代时都会重新创建,并在循环内声明。那么在上一次迭代中创建的数据会发生什么?

由于它的引用被添加到一个数组中,数据本身被保留下来,被数组中的那个引用引用,并且只被那个引用引用。正是您想要的,只能通过数组访问的单独数据。

在这种情况下,这优于 push @res, { %h },后者也有效,因为在保存数据时避免了数据复制,也就是说,仅更改其所有权。


并且 ff 数据通过 @a1 更改,如 $a1[0]->{key} = 'val';,然后通过 $h{key} 也可以看到新值。