我今天花了太多时间调试其中一个阴险的小错误。
这或多或少是我所做的:
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my $test = new MyTest('test');
say $test->to_string for 1..3;
package MyTest;
sub new {
my $class = shift;
my $parm = shift;
return bless \$parm, $class;
}
sub to_string {
my $self = shift;
my $string = 'Hello!' if 0;
$string .= $$self;
return $string;
}
请注意,由于进行了错误测试,因此不会评估my $string
。 (当然,我失去了很多时间的代码没有if 0
!)
我意识到编译器并不知道测试会是错误的,但是它不应该抱怨我使用的是一个可能未在下一行声明的变量?
另外,我希望这会导致运行时错误,但perl
只是给了我
test
testtest
testtesttest
为什么没有错误?这是一个错误还是一个功能?
答案 0 :(得分:7)
my $foo;
假设要分配一个新的var(有点像Scalar* foo = new Scalar();
),但这样效率很低,所以没有这样实现。
my
具有声明变量的编译时效果。这有效地创造了它。由于它发生在编译时,它不受if
的影响。像往常一样,变量的范围是包含它的块(curlies)。
my
具有在堆栈上放置指令以在范围退出时用新的变量替换变量的运行时效果。 (如果没有任何东西抓住它的引用,它只会被清除。)这就是被跳过的。
在不同于条件的条件下使用变量是未定义(不允许)的行为。
如果您正在尝试创建词法范围的持久变量,请使用
{
my $x = init();
sub foo {
... $x ...
}
}
或
use feature qw( state ); # Require 5.10+
sub foo {
state $x = init(); # init() is only called the first time foo() is called.
... $x ...
}
答案 1 :(得分:5)
这是一个更严格的例子:
use strict;
use warnings;
sub to_string {
my $param = shift;
my $string = 'Hello!' if 0;
$string .= $param;
return $string;
}
print to_string("foo"), "\n";
print to_string("bar"), "\n";
print to_string("baz"), "\n";
输出:
foo
foobar
foobarbaz
基本上,您不应该使用语法my $var = $val if $cond
声明和有条件地初始化变量,因为行为将是意外的。 Perl Bug 5 - my $var = val if (..) doesn't work properly
相反,在这种情况下总是使用三元组:
my $var = $cond ? $val : undef;