File::Find 和 wanted 子程序这个问题比原始标题("原型和子程序的前向声明"!)简单得多.我希望答案,无论多么简单,都能帮助我理解子程序/函数,原型和范围以及File::Find模块.
使用Perl,子程序几乎可以出现在任何地方,你通常不需要进行前向声明(除非sub声明了一个原型,我不知道如何在Perl中采用"标准"方式).对于我通常用Perl做的事情,这些不同的运行方式之间没有什么区别somefunction:
sub somefunction; # Forward declares the function
&somefunction;
somefunction();
somefunction; # Bare word warning under `strict subs`
Run Code Online (Sandbox Code Playgroud)
我经常find2perl用来生成代码,我将这些代码整合到脚本的一部分中.这可能是糟糕的风格,现在我的脏衣服是公开的,但所以它是:-)因为File::Find该wanted功能是一个必需的子程序 - find2perl创建它并添加sub wanted;到它创建的结果脚本.有时候,当我编辑脚本时,我会从中移除" sub" sub wanted并最终为&wanted;或wanted();.但如果没有sub wanted;前瞻声明表格,我会收到此警告:
Use of uninitialized value $_ in lstat at findscript.pl line 29
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么会发生这种情况,这是一个真正的问题吗?这只是"警告",但我想更好地理解它.
$_是本地化的sub wanted {}.如果我使用wanted();而不是sub wanted;?为什么它会被定义?wanted某处使用原型?我错过了一些明显的东西Find/File.pm吗?wanted返回代码引用吗?(???)我的猜测是前向声明表单wanted以某种方式"初始化" ,以便第一次使用时没有空的默认变量.我想这就是原型 - 即使是Perl原型,如它们存在 - 也会起作用.我尝试使用Perl源代码来了解在sub使用sub function而不是使用函数调用函数时正在做什么function(),但这可能超出了我的目的.
任何帮助加深(并加快)我对此的理解都非常感谢.
编辑:这是我在Stack Overflow上使用find2perl输出创建的最新示例脚本.如果除去sub 从sub wanted;你应该得到同样的错误.
编辑:正如我在下面的评论中指出的那样(但我也会在这里标记):几个月来我一直在使用Path::Iterator::Rule而不是File::Find.它需要perl >5.10,但我永远不必在奇怪的"永不升级"的站点部署生产代码,5.8.*只有策略Path::Iterator::Rule已成为我从不想做的那些模块之一.也很有用Path::Class.干杯.
Dav*_* W. 12
我不是File :: Find的忠实粉丝.它只是不工作的权利.该find命令不返回文件列表,因此您必须使用非本地数组变量find来捕获您找到的文件列表(不好),或将整个程序放在您想要的子程序中(更糟).另外,单独的子程序意味着您的逻辑与find命令是分开的.这只是丑陋的.
我所做的是wanted在我的find命令中内联我的子程序.子程序保留在查找中.另外,我的非本地数组变量现在只是我find命令的一部分,看起来并不那么糟糕
这是我如何处理File::Find- 假设我想要具有.pl后缀的文件:
my @file_list;
find ( sub {
return unless -f; #Must be a file
return unless /\.pl$/; #Must end with `.pl` suffix
push @file_list, $File::Find::name;
}, $directory );
# At this point, @file_list contains all of the files I found.
Run Code Online (Sandbox Code Playgroud)
这完全相同:
my @file_list;
find ( \&wanted, $directory );
sub wanted {
return unless -f;
return unless /\.pl$/;
push @file_list, $File::Find::name;
}
# At this point, @file_list contains all of the files I found.
Run Code Online (Sandbox Code Playgroud)
衬里看起来更好看.而且,它将我的代码保持在一起.另外,我的非本地数组变量看起来并不那么怪异.
我也喜欢以这种特殊的方式利用更短的语法.通常,我不喜欢使用推断$_,但在这种情况下,它使代码更容易阅读.我原来的通缉与此相同:
sub wanted {
my $file_name = $_;
if ( -f $file_name and $file_name =~ /\.pl$/ ) {
push @file_list, $File::Find::name;
}
}
Run Code Online (Sandbox Code Playgroud)
File::Find使用并不是那么棘手.你只需要记住:
return转到下一个文件.$_ 包含没有目录的文件名,您可以使用它来测试文件.$File::Find::name.$File::Find::dir.而且,最简单的方法是将所需的文件推送到数组中,然后在程序中使用该数组.
删除subfrom sub wanted;只是调用wanted函数,而不是前向声明.
但是,该wanted函数尚未设计为直接从您的代码中调用 - 它被设计为由File :: Find调用.File :: Find $_在调用它之前做了很有用的事情,比如填充.
这里没有必要转发声明wanted,但如果要删除前向声明,请删除整sub wanted;行 - 而不仅仅是单词sub.