用我的Perl函数作用域

时间:2018-04-02 14:39:04

标签: perl scope

我对以下两个代码段之间的行为差​​异感到困惑:

$x = 8;
sub a {
    sub b {
        print "B: $x\n";
    }
    my $x = 3;
    &b();
}
&a();

$x = 8;
sub a {
    my $x = 3;
    sub b {
        print "B: $x\n";
    }
    &b();
}
&a();

当第一个输出B:8时,第二个输出B:3。它们不应该输出相同的值,因为sub b的外部范围应该是sub a?功能的不同位置如何产生影响?

2 个答案:

答案 0 :(得分:5)

其他人已经指出了嵌套sub的问题,但这是我对你的问题理解的答案:

my声明的“范围”在包含my的语句之后开始,而不是在它出现的块的开头。或者,这两个都可以工作:

$ perl -wMstrict -le 'sub foo { my $bar="quz"; print $bar; } foo()'
quz
$ perl -wMstrict -le 'sub foo { print $bar; my $bar="quz"; } foo()'
Global symbol "$bar" requires explicit package name (did you forget to declare "my $bar"?) at -e line 1.
Execution of -e aborted due to compilation errors.

另外,请注意以下事项:

my $x = 3;
{
    my $x = $x + 5;
    print "1: $x\n";  # prints "1: 8"
}
print "2: $x\n";      # prints "2: 3"

在您的第一段代码中,在您声明sub b时,Perl只知道全局$x = 8,这就是print "B: $x\n"正在使用的内容。在第二段代码中,Perl看到了my $x = 3,所以它就是它的用途。如果您不使用嵌套的sub s:

,也会出现此效果
my $x = 8;
sub a {
    my $subb = sub {
        print "B: $x\n";
    };
    my $x = 3;
    $subb->();
}
a();  # prints "B: 8"

my $x = 8;
sub a {
    my $x = 3;
    my $subb = sub {
        print "B: $x\n";
    };
    $subb->();
}
a();  # prints "B: 3"

答案 1 :(得分:3)

这个问题源于嵌套的命名subs。

没有理由在Perl中使用嵌套的名称subs,因为内部sub不以作用域为外部。

相反,请使用:

sub p {
    my ($x) = @_;

    local *q = sub {
        say $x;
    };

    q();
}

p($_) for 3, 4;

sub p {
    my ($x) = @_;

    my $q = sub {
        say $x;
    };

    $q->();
}

p($_) for 3, 4;