7

我知道将标量传递给子实际上是传递引用,但由于我是 perl 新手,我仍然做了以下测试:

#!/usr/bin/perl
$i = 2;
subr(\$i);
sub subr{
    print $_[0]."\n";
    print $$_[0]."\n";
}

我以为第一行会打印一个地址,第二行会返回数字,但第二行是空行。我被其他人指出要这样做:${$_[0]}它会打印数字。但她不知道没有 {} 无法正常工作的原因以及与 {} 一起工作的原因。那么发生了什么?

4

4 回答 4

16

这是因为你的第二个打印语句相当于这样做......

my $x = $$_; print $x[0];

当你想要的是

my $x = $_[0]; print $$x;

换句话说,取消引用发生在计算数组下标之前。

当您添加这些 curl-wurlies 时,它会告诉 perl 如何根据需要解释表达式;它将$_[0]首先评估,然后取消引用以获取值。

于 2011-05-03T15:32:38.450 回答
8

这是一个评估顺序的事情。

  $$_[0] is evaluated as {$$_}[0]

这是标量变量 $_ 的引用的第 0 个元素。它首先获取参考,然后尝试找到它的第 0 个元素。

  ${$_[0]}

这是对数组 @_ 的第 0 个元素的引用。它首先找到第 0 个元素,然后引用它。

如果您在代码顶部设置use strict和,您将在第一次尝试时看到大量关于未定义值的警告。use warnings

于 2011-05-03T15:33:28.700 回答
3

$$_[0]就像$foo[0],仅用 $_ 代替数组名称。这意味着 $_ 被视为数组引用,并且表达式根本不涉及标量引用$_[0]$_->[0]是等效的,使用替代->语法。取消引用的语法可能看起来随意且难以记住,但有潜在的意义和顺序;在http://perlmonks.org/?node=References+quick+reference上有一个很好的介绍。

于 2011-05-03T17:19:49.533 回答
1

您不必传递对$i. 该符号$_[0]是您调用它时的别名$isubr( $i )

use strict;
use warnings;
use Test::More tests => 2;

sub subr{ $_[0]++ } # messing with exactly what was passed first
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );

另一个例子是这样的:

use strict;
use warnings;
use Test::More tests => 6;
use Test::Exception;

sub subr{ $_[0]++ }
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );

sub subr2 { $_[0] .= 'x'; }
dies_ok { subr2( 'lit' ); } 'subr2 *dies* trying to modify a literal';
lives_ok { 
    my $s = 'lit';
    subr2( $s );
    is( $s, 'litx', q[$s eq 'litx'] );
    subr2(( my $s2 = 'lit' ));
    is( $s2, 'litx', q[$s2 eq 'litx'] );
} 'subr2 lives with heap variables';

输出:

ok 1 - $i == 2
ok 2 - $i == 3
ok 3 - subr2 *dies* trying to modify a literal
ok 4 - $s eq 'litx'
ok 5 - $s2 eq 'litx'
ok 6 - subr2 lives with heap variables
1..6
于 2011-05-03T16:29:16.547 回答