为什么perl不关心我是否在狭窄下宣布我的变量?

sco*_*ozy 2 perl scope

我今天花了太多时间调试其中一个阴险的小错误.

这或多或少是我所做的:

#!/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)

为什么没有错误?这是一个错误还是一个功能?

ike*_*ami 7

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)


Mil*_*ler 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";
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)