为什么数组中哈希的重复条目引用Perl中的第一个条目

VB_*_*VB_ 2 arrays perl hash

重申这个问题,为什么数组中重复的哈希条目引用了Perl中的第一个条目?如果我弄错了,请更正我的术语,但是当我将相同的哈希引用推送到具有以下代码的数组中时:

use strict;
use warnings;
use Data::Dumper qw(Dumper);

my @array;
my %hash = (foo => 'foo', bar => 'bar');

for (1..3) {
    push @array, \%hash;
}

print Dumper @array;
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

$VAR1 = { 
          'bar'=> 'bar',
          'foo'=> 'foo'             
        };
$VAR2 = $VAR1;
$VAR3 = $VAR1;
Run Code Online (Sandbox Code Playgroud)

我希望看到以下结果:

$VAR1 = { 
          'bar'=> 'bar',
          'foo'=> 'foo'             
        };
$VAR2 = { 
          'bar'=> 'bar',
          'foo'=> 'foo'             
        };
$VAR3 = { 
          'bar'=> 'bar',
          'foo'=> 'foo'             
        };
Run Code Online (Sandbox Code Playgroud)

这种行为是因为Perl的基本概念还是因为Data::Dumper

sim*_*que 7

基本上你已经自己说过了(强调我的).

如果我弄错了,请更正我的术语,但是,当我将相同的哈希引用推送到具有下面代码的数组中时

那是因为你推入了哈希的引用.在循环的每次迭代中,它始终是相同的散列,因此每个引用都转到相同的散列.

如果您使用数据::打印机p,输出如下,我觉得这不是更清晰的数据::自卸车之一.

[
    [0] {
        bar   "bar",
        foo   "foo"
    },
    [1] var[0],
    [2] var[0]
]
Run Code Online (Sandbox Code Playgroud)

很明显,它指的是同样的事情.现在,如果您运行此代码:

for (@array) {
    say $_;
}
Run Code Online (Sandbox Code Playgroud)

输出将是同一地址的三倍.

HASH(0x2755150)
HASH(0x2755150)
HASH(0x2755150)
Run Code Online (Sandbox Code Playgroud)

参考的整个想法是引用相同的东西.这是一个非常强大的工具,因为这样可以节省内存.如果你$hash确实不只是一个很小的哈希值,而是一个大对象(比方说,一个WWW ::机械化对象,可容纳解析的HTML文档),周围路过这将是超贵.

但是通过引用,获得它的每一段代码都可以共享它.这样更有效率.

有关这方面的更多信息,您应该阅读perlrefperlreftut.


但是,如果您需要副本,则需要构建自己的哈希引用,而不是引用已有的哈希.这就是@toolic在评论中所说的.

my %hash = (foo => 'foo', bar => 'bar');

for (1..3) {
    push @array, { %hash };
}
Run Code Online (Sandbox Code Playgroud)

如果你有一个现有的参考,并且你想要一个副本,首先取消引用它.

my $ref = { foo => 'bar' };
my $shallow_copy = { %{ $ref } };
Run Code Online (Sandbox Code Playgroud)

如果您需要更深层次的副本,请查看此答案.