下面是一个例子:
sub merge_xml {
foreach my $repository ('repo1', 'repo2') {
my @xml_files;
sub match_xml {
my $filename = $File::Find::dir . '/' . $_;
if ($filename =~ m%/(main|test)\.xml$%) {
push(@xml_files, $filename);
}
}
find(\&match_xml, $repository);
print Dumper(\@xml_files);
}
}
我得到警告:
Variable "@xml_files" will not stay shared at ./script/src/repair.pl line 87.
如何解决这个问题?
PS查找与File::Find相同
3条答案
按热度按时间bq8i3lrv1#
“嵌套的”命名子例程实际上不是--它们被编译为单独的子例程,因此将它们写为“嵌套的”只会产生误导。
此外,这会产生一个问题,因为“inner”子例程应该关闭它所使用的变量
@xml_files
,该变量在每次新调用时都会被重新定义,成为词法闭包。但是,在编译时构建的sub子例程不是词法闭包,它只在第一次调用时保留对该值的引用,因此它只在第一次调用外部sub子例程(这里是merge_xml
)时才起作用。不过我们确实收到了警告。使用
use diagnostics;
(或者在perldiag中查看)变量“$x”将不会在-e行1(#1)中共享
(W闭包)内部(嵌套)命名子例程正在引用外部命名子例程中定义的词法变量。
当调用内部子例程时,它将看到外部子例程的变量的值,就像它在 * 第一次 * 调用外部子例程之前和期间一样;在这种情况下,在第一次调用外部子程序完成后,内部和外部子程序将不再共享变量的公共值。2换句话说,变量将不再被共享。
这个问题通常可以通过使用sub {}语法使内部子例程匿名来解决。当引用外部子例程中的变量的内部匿名子例程被创建时,它们会自动重新绑定到这些变量的当前值。
因此,取出“内部”子函数(
match_xml
),并正常使用“外部”子函数(merge_xml
)。或者由于在这种情况下不能传递到X1 M6 N1 X的X1 M7 N1 X,因此可以使数组处于这样的范围内,以便被视为是需要的。或者,由于
match_xml
的目的是作为find的“wanted”函数,因此可以使用匿名sub来实现该目的,这样就不需要单独的命名sub或者将coderef存储在变量中,如Ed Heal's answer所示
uidvcgyl2#
在zdim的帮助下,我想出了:
csga3l583#
我可以建议另一种选择吗?通过使用工厂函数,您可以消除每次手工编写
find
子例程的需要。工厂是一个生成另一个函数的函数(在这里是子例程)。你给它一些参数,它就用这些参数创建一个自定义的子例程。我的例子使用了一个闭包,但是如果闭包由于某种原因成本很高,你也可以用字符串
eval
来构建它。高温