相信很多人都写过下面这种函数,把参数当作hash引用来赋值:

sub foo {
  my $hash = shift;
  $hash->{foo} = 'bar';
}

然后这样调用:

foo($a);

调用之后,$a就变成了一个hash引用,里面包含了 foo => 'bar' 这一对值。 当然你可能会说,干嘛要在foo里面修改参数,直接return $hash不行吗。 当然可以,而且我也推荐使用return的方式, 不过有时候foo函数可能会很复杂,或者由于其他的原因而不得不使用修改参数的方式。

且慢!这种用法有时候会会失败。看下面的例子:

#!/usr/bin/perl

use Data::Dumper;

sub foo {
    my $h = shift;
    $h->{hello} = 'World!';
}

my $a;
my $b = {};
foo($a); print Dumper($a);
foo($b); print Dumper($b);

运行结果:

$VAR1 = undef;
$VAR1 = {
          'hello' => 'World!'
        };

为什么$a执行foo后仍然为undef,而$b就有值?

这是因为,my $a; 没有对$a初始化,此时$a的值为undef。 而调用foo时,参数实际上是传值调用,$aundef值被赋给了$h变量, 此时$h = undef。而下一行将$h作为hash引用赋值时,系统会自动为$h赋一个空引用作为初始值。 ——但是,这个空引用以及接下来赋给的 hello => 'World!' 的值不会传回给外面的 $a,因为是值传递!

$b则不同,初始化成一个空hash引用,这样传递给foo的就是个真正的引用值, 这样 hello => 'World!'的赋值可以赋给该引用。

所以,在使用hash引用时,初始化是非常必要的。