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}
也可以看到新值。
我正在 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}
也可以看到新值。