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



我正在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,使其不会神奇地出现在不同的数组中?

该代码添加对现有(命名)哈希的引用

push @a1, %h;

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

再次添加它,即使哈希更改,您也只需添加相同的旧引用。

你想要的是制作一个数据副本并添加一个引用 - 一个匿名哈希

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;
}

现在这是可以的,因为哈希%h在每次迭代时都会重新创建,并在循环中声明。 那么,在上一次迭代中创建的数据会发生什么情况呢?

由于它的引用被添加到数组中,因此数据本身被保留,由数组中的该引用引用,并且仅由该引用引用。正是您想要的,只能通过阵列访问的单独数据。

在这种情况下,这比push @res, { %h }更可取,后者也有效,因为在保留数据时避免了数据副本,可以说,只是更改其所有权。


ff数据通过@a1更改,就像$a1[0]->{key} = 'val';一样,然后新值也通过$h{key}看到。

最新更新