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