我正在尝试在Perl
中使用哈希处理时调试一些奇怪的行为。
我正在将哈希(而不是ref)传递给子例程,并且由于某种原因它会对其进行更新。
some_sub($a,%{$hash});
sub some_sub {
my ($a,%hash) = @_;
my @struct;
while (my ($dir, $data) = each %hash) {
foreach my $id (keys(%{$data})) {
my $entry = $data->{$id};
$entry->{id} = $id;
my $parent = $data->{$entry->{id}};
unless ($parent) {
push @struct, $entry
} else {
push @{$parent->{children}},$entry;
}
}
}
}
my %h= %{$hash};
print Dumper(\%h);
子some_sub
确实更改了%hash
,但仅更改了内部范围,因此不应更改外部%hash
的数据。另外,我将散列作为散列而不是散列引用传递。我怀疑子some_sub
会将存储器地址插入%hash
中,但不确定。
我应该如何调试和解决此问题?
编辑:我还尝试了将哈希引用传递给子例程,并在对新哈希执行所有操作时将哈希引用解引用到另一个哈希中。
答案 0 :(得分:9)
哈希中的每个值都是标量。如果您有嵌套的哈希,则内部哈希存储为标量-哈希引用。因此,在更改嵌套结构时,更改也会发生在引用的哈希中,该哈希也从原始哈希中引用。
#! /usr/bin/perl
use warnings;
use strict;
sub change {
my %hash2 = @_;
for my $key (keys %hash2) {
++$_ for values $hash2{$key};
}
}
my %hash = (a => {b => 12, c => 24});
change(%hash);
use Data::Dumper; print Dumper \%hash;
输出:
$VAR1 = {
'a' => {
'b' => 13,
'c' => 25
}
};
答案 1 :(得分:4)
参数作为标量的平面列表传递给函数,因此
some_sub($a, %{$hash})
在$a
some_sun($a, key, value, ...);
将这些键值对分配给函数中的哈希值之后,您便可以直接使用引用(您的哈希值),因此调用者中的数据将被更改。
没有说明目的是什么,但是如果您不希望调用者的数据更改一个解决方法,则是避免更改子程序中的数据,也许是通过为处理遇到的每个引用引入局部变量。如果它们本身可能包含引用,您仍然需要非常小心。
创建散列的完整深层副本较为简单,如果数据结构并不庞大。例如
use Storable qw(dclone);
some_sub($v, $hashref);
sub some_sub {
my ($var, $hr) = @_;
my $cloned_hashref = dclone($hr);
# work away with $cloned_hashref
}