我很难让我的一个模块来编译看似可变范围的问题,但我不明白为什么。
示例代码:
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
语句。
答案 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");
...
}