我在理解perl中的引用时遇到困难。这是一个简短的perl脚本来解释我的问题[我使用perl-5.8.3运行此代码]:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
foo(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
bar(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
sub foo {
my($h1, $h2) = @_;
$h2 = $h1;
print Dumper($h2);
}
sub bar {
my($h1, $h2) = @_;
%{$h2} = %{$h1};
}
我想在两个子程序中,$ h1和$ h2都是本地变量。仍然,bar()实际上改变了原始%b的值,而foo()则没有。那是为什么?
答案 0 :(得分:6)
sub foo {
my($h1, $h2) = @_; # copy two hash references into lexicals
$h2 = $h1; # copy the value in lexical $h1 into $h2
# $h2 looses its binding to the hash ref
print Dumper($h2);
}
如果值包含字符串或任何其他简单值,则这与您将获得的行为完全相同。
sub bar {
my($h1, $h2) = @_; # copy two hash references into lexicals
%{$h2} = %{$h1}; # the hash referred to by $h1 is unpacked into a list
# the hash referred to by $h2 is exposed as an lvalue
# the assignment operator installs the rhs list into
# the lvalue, replacing any previous content
}
所以基本上,在第一个例子中,您只是处理值,并且正常值语义适用。在第二种情况下,您将取消引用这些值,这会将它们变回高级类型(在本例中为HASH)。
答案 1 :(得分:2)
$h2
是一个包含引用的词法变量。更改$h2
只会替换其中的引用。
%{$h2}
是$h2
引用的哈希(又名%b
),因此更改%{$h2}
(又名%b
)会更改{{1引用的哈希值(又名$h2
)。
您似乎期望更改一个变量(%b
)会改变另一个变量($h2
),但我不知道您为何会有这样的期望。他们甚至不是相同的变量类型!当标量没有元素时(至少与散列的意义不同),如何通过更改标量来尝试更改散列元素。
答案 2 :(得分:1)
sub foo {
my($h1, $h2) = @_;
$h2 = $h1;
}
让我们更轻松:$h1
指向内存位置#1,$h2
指向内存位置#2。您的语句$h2 = $h1
现在使$h2
也指向内存位置#1。
内存位置#1的内容是否已更改?否。内存位置#2的内容是否已更改?否。
离开子例程后,$h1
和$h2
不再存在。
sub bar {
my($h1, $h2) = @_;
%{$h2} = %{$h1};
}
当你说%{$h1}
时,你现在正在谈论内存位置#1的内容。您在作业中所做的是将内存位置#1的内容复制到内存位置#2。请注意,$h1
仍指向内存位置#1,$h2
仍指向内存位置#2。因此,$h1
和$h2
的值不会改变,但他们指出的内容会发生变化。
现在,让我们看一下%a
和%b
。 %a
的内容位于内存位置#1,%b
的内容位于内存位置#2。在sub foo
中,我们未更改内存位置#2中的信息,因此%b
的值未发生变化。
在sub bar
中,我们弄乱了内存位置#2的内容,因此%b
(将其内容存储在内存位置#2中)的值发生了变化。
顺便提一下,请注意在子程序调用后更改%a
根本不会更改%b
。它们可能共享相同的内容,但它们不是同一个变量。
答案 3 :(得分:0)
这与传递或子程序无关。这只是混淆了这个问题。如果你在不调用子程序的情况下考虑相同的代码,你会更好地理解它:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
my $h1 = \%a;
my $h2 = \%b;
$h2 = $h1;
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
$h1 = \%a;
$h2 = \%b;
%{$h2} = %{$h1};
print "+==After fn call==+\n";
print Dumper(\%a, \%b);