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

问题描述 投票:0回答:1

我正在 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
中,但当数据写入
$h{b}
时,
@a1
并不存在。

我不希望

b
出现在
@a1
中,而且,它不应该出现。

如何修改

%h
,使其不会神奇地出现在不同的数组中?

perl reference
1个回答
10
投票

该代码将 引用添加到现有(命名)哈希,

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

现在 
this

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

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

在这种情况下,这比

push @res, { %h }

更好,后者也有效,因为在保留数据时可以避免数据副本,也就是说,仅更改其所有权。



ff 数据通过 @a1 更改,如

$a1[0]->{key} = 'val';
,然后也可以通过
$h{key}
看到新值。
    

© www.soinside.com 2019 - 2024. All rights reserved.