使用在Continue块的For循环中声明的词法变量

时间:2019-03-27 22:31:55

标签: perl

我很难让我的一个模块来编译看似可变范围的问题,但我不明白为什么。

示例代码

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在外部foreach循环(标记为PATH)内的第2行被声明为词法变量。

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

  

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

为了能够增加循环变量,继续语句是否会被视为与其所附加的循环相同的词法作用域的一部分?

我想念什么?


注意:该模块是Moo类,因此尽管我在when you use Moo we enable strict and warnings的任何地方都没有明确的use strict语句。

2 个答案:

答案 0 :(得分:4)

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

如果语法是这样的:

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

然后我希望$x可见。 IIRC,perl 6具有类似的内容,但是在perl 5中,continue BLOCK在循环的块之外,因此看不到该块内的词法变量。

答案 1 :(得分:3)

保证在评估continue块之前已声明循环变量,以便可以将变量提供给continue块。

但是可以跳过循环块的任何部分(例如使用next),因此Perl不知道在编译时continue时将声明哪个循环块变量输入了代码块,因此无法使它们continue中可用。


如果您不满意文件句柄自动关闭(例如,由于要检测写错误),则可以使用范围保护代替continue块。

use Sub::ScopeFinalizer qw( scope_finalizer );

for my $qfn (@qfns) {
   my $fh;
   my $guard = scope_finalizer {
      if ($fh) {
         close($fh)
            or die("Error writing to \"$qfn\": $!\n");
      }
   };

   open($fh, '>', $qfn)
      or die("Can't create \"$qfn\": $!\n");

   ...
}