有人可以解释为什么Perl会以这种方式行事(变量范围)吗?

时间:2015-11-18 15:08:39

标签: perl

我的测试是这样的:

use strict;
use warnings;

func();
my $string = 'string';
func();

sub func {
    print $string, "\n";
}

结果是:

Use of uninitialized value $string in print at test.pl line 10.

string

Perl允许我们在定义函数之前调用它。但是,当函数使用仅在函数调用之后声明的变量时,该变量似乎未定义。这种行为是否记录在某处?谢谢!

2 个答案:

答案 0 :(得分:12)

my中记录了perl的行为 - 归结为此 - $string知道my在范围内 - 因为my告诉它如此。

  

my运算符声明列出的变量在词法上限制在封闭块,条件(if / unless / elsif / else),循环(for / foreach / while / until / continue),子例程,eval或do /要求/使用&#d;文件。

这意味着它的范围是'从他们第一次看到的地方开始#39;直到当前'块的结束括号。 (或者在你的例子中 - 代码的结尾)

但是 - 在您的示例$string 还会分配一个值。

这个范围确定过程在编译时发生 - 其中perl检查它是否有效使用strict。 (感谢#!/usr/bin/env perl use strict; use warnings; my $string; #undefined func(); $string = 'string'; func(); sub func { print $string, "\n"; } )。但是 - 它无法知道值是什么,因为在代码执行期间可能会发生变化。 (并且非常容易分析)

因此,如果你这样做,可能会更清楚一下:

$string
在这两种情况下,

my都在范围内 - 因为undef发生在编译时 - 在子程序被调用之前 - 但它没有设置超出默认值{的值{1}}在第一次调用之前。

请注意这与:

形成鲜明对比
#!/usr/bin/env perl
use strict;
use warnings;

sub func {
    print $string, "\n";
}

my $string; #undefined
func();
$string = 'string';
func();

由于声明sub时出现了哪些错误,因此$string不在范围内。

答案 1 :(得分:4)

首先,我会考虑这种未定义的行为,因为它会像my一样跳过执行my $x if $cond;

尽管如此,这种行为目前是一致和可预测的。在这种情况下,如果保证未定义行为通知的优化没有退出,它的行为正好

在编译时,my具有声明和分配变量 [1] 的效果。 Scalars在创建时初始化为undef。数组和散列是空的。

编译器遇到

my $string,因此创建了变量。但是,由于您尚未执行任务,因此在第一次调用func期间,它仍然具有默认值(未定义)。

此模型允许通过闭包捕获变量。

示例1:

{
   my $x = "abc";
   sub foo { $x }   # Named subs capture at compile-time.
}

say foo();  # abc, even though $x fell out of scope before foo was called.

示例2:

sub make_closure {
   my ($x) = @_;
   return sub { $x };   # Anon subs capture at run-time.
}

my $foo = make_closure("foo");
my $bar = make_closure("bar");

say $foo->();  # foo
say $bar->();  # bar
  1. 可能会推迟分配,直到实际使用该变量。