首页 > 解决方案 > 在 Continue 块中使用 For 循环中声明的词法变量

问题描述

我无法让我的一个模块编译看起来是一个变量范围问题,但我不明白为什么。

示例代码

PATH: foreach my $path (@paths) {
    open(my $file, '<', $path) or next PATH;

    my %properties;
    LINE: while (<$file>) {
        $_ =~ /$property_regex/ or next LINE;
        $properties{$1} = $2;
    }

    foreach (@property_keys) {
        unless ($properties{$_}) {
            # do stuff
            next PATH;
    }

    if ( $irrelevant_condition ) {
        # do stuff
        next PATH;
    }

    foreach my $new_var (@new_list) {
        # do stuff (does not iterate PATH loop)
    }
} continue {
    if (defined $file) { close($file) or die; }
}

转换为上面的精简代码,我得到的错误是:

全局符号“$file”在第 25 行需要明确的包名

也就是说,它似乎在抱怨底部块中的$file使用。continue如您所见,$file在第 2 行中,在外部 foreach 循环(标记为 PATH)内将其声明为词法变量。

但是,基于perldoc for continue,我希望$file仍在范围内:

[...] 它总是在条件即将被再次评估之前执行,就像 C 中 for 循环的第三部分一样。因此它可以用来增加循环变量,即使循环已经继续[...]

为了能够增加循环变量,是否将 continue 块视为与其所附加的循环相同的词法范围的一部分?

我错过了什么?


注意:这个模块是一个 Moo 类,所以虽然我在任何地方都没有明确的use strict声明,但当你使用 Moo 时,我们启用了 strict 和 warnings

标签: perl

解决方案


您的$path变量仍在 内的范围内continue BLOCK,但forBLOCK 内的内容超出范围,因为您已经到达该 BLOCK 的末尾(您已经打到了大括号/退出了大括号)。但是,$path变量不在大括号内,因此可以在大括号内可见continue BLOCK(即使在大括号之外不可见)。

如果语法是这样的:

for (...)
{
 $x = stuff();
 continue { more_stuff($x) }
}

那么我希望$x是可见的。IIRC,perl 6 有这样的东西,但在 perl 5 中,continue BLOCK在循环块之外,因此看不到该块内的词法变量。


推荐阅读