您尚未发布用于构建哈希的实际代码,但我认为它看起来像这样:
foreach my $i (1 .. 3) {
%hash2 = (number => $i, foo => "bar", baz => "whatever");
$hash1{$i} = \%hash2;
}
(实际上,我猜,在您的实际代码中,您可能正在循环中从文件中读取数据并基于它while (<>)
分配值,但循环将用于演示目的。)%hash2
foreach
如果您运行上面的代码并%hash1
使用 Data::Dumper 转储结果,您将获得输出:
$VAR1 = {
'1' => {
'baz' => 'whatever',
'number' => 3,
'foo' => 'bar'
},
'3' => $VAR1->{'1'},
'2' => $VAR1->{'1'}
};
为什么会这样?嗯,这是因为里面的值%hash1
都是指向同一个哈希的引用,即%hash2
. 当您在循环中分配新值时%hash2
,这些值将覆盖 中的旧值%hash2
,但它仍然是相同的哈希值。Data::Dumper 只是强调了这一事实。
那么,您该如何解决呢?好吧,有(至少)两种方法。一种方法是替换\%hash2
,它提供了对 的引用%hash2
, with将 的内容{ %hash2 }
复制到%hash2
一个新的匿名哈希中并返回对它的引用:
foreach my $i (1 .. 3) {
%hash2 = (number => $i, foo => "bar", baz => "whatever");
$hash1{$i} = { %hash2 };
}
另一种(IMO 更可取的)方法是%hash2
在循环中声明为(词法范围的)局部变量,使用my
:
foreach my $i (1 .. 3) {
my %hash2 = (number => $i, foo => "bar", baz => "whatever");
$hash1{$i} = \%hash2;
}
这样,循环的每次迭代都将创建一个名为 的新的不同哈希%hash2
,而在先前迭代中创建的哈希将继续%hash1
独立存在(因为它们是从 引用的)。
顺便说一句,如果你遵循标准的 Perl 最佳实践,你一开始就不会遇到这个问题,特别是:
遵循这些最佳实践,上面的示例代码如下所示:
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my %hash1;
foreach my $i (1 .. 3) {
my %hash2 = (number => $i, foo => "bar", baz => "whatever");
$hash1{$i} = \%hash2;
}
print Dumper(\%hash1);
正如预期的那样,它将打印:
$VAR1 = {
'1' => {
'baz' => 'whatever',
'number' => 1,
'foo' => 'bar'
},
'3' => {
'baz' => 'whatever',
'number' => 3,
'foo' => 'bar'
},
'2' => {
'baz' => 'whatever',
'number' => 2,
'foo' => 'bar'
}
};