16

比较使用 perl -w -Mstrict

# case Alpha
print $c;

...

# case Bravo
if (0) {
  my $c = 1;
}

print $c;

...

# case Charlie
my $c = 1 if 0;
print $c;

Alpha并且Bravo都抱怨全局符号没有明确的包名称,这是可以预料的。但Charlie没有给出相同的警告,只是该值未初始化,闻起来很像:

# case Delta
my $c;
print $c;

引擎盖下到底发生了什么?(即使永远不应该为生产代码编写这样的东西)

4

3 回答 3

15

您可以将my声明视为在编译时和运行时具有操作。在编译时,一个my声明告诉编译器记下一个符号存在并且在当前词法作用域结束之前一直可用。该声明中符号的赋值或其他使用将在运行时进行。

所以你的例子

my $c = 1 if 0;

就好像

my $c;         # compile-time declaration, initialized to undef
$c = 1 if 0;   # runtime -- as written has no effect

请注意,这种编译时/运行时的区别允许您编写这样的代码。

my $DEBUG;    # lexical scope variable declared at compile-time
BEGIN {
    $DEBUG = $ENV{MY_DEBUG};   # statement executed at compile-time
};

现在你能猜出这个程序的输出是什么吗?

my $c = 3;
BEGIN {
    print "\$c is $c\n";
    $c = 4;
}
print "\$c is $c\n";
于 2012-06-29T20:22:04.563 回答
8

mob 的回答很好地解释了当前发生的事情(以及为什么),但不要忘记它perldoc perlsyn告诉我们:

注意:mystateour用语句修饰符条件或循环构造(例如 )修改的行为my $x if ...undefined。变量的值my可以是 undef,任何先前分配的值,或者可能是其他任何值。不要依赖它。未来版本的 perl 可能会做一些与您尝试使用的 perl 版本不同的事情。这里是龙。

不要指望那个结果或对它的解释在未来的 Perl 版本中仍然是正确的。(虽然它可能会。)

于 2012-06-30T15:29:50.303 回答
3

多年来,“my $foo = val if cond ”构造及其未定义的行为多次困扰着我。我希望编译器可以简单地拒绝它(为什么要在具有未定义行为的语言中保留一些东西?!),但大概出于向后兼容性或其他原因,这不能完成。我发现的最佳解决方案是使用 perlcritic 来防止它:

http://search.cpan.org/perldoc?Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations

于 2012-07-02T16:12:31.017 回答