为啥 Perl 文件 glob() 不能在标量上下文中的循环之外工作?
Posted
技术标签:
【中文标题】为啥 Perl 文件 glob() 不能在标量上下文中的循环之外工作?【英文标题】:Why doesn't Perl file glob() work outside of a loop in scalar context?为什么 Perl 文件 glob() 不能在标量上下文中的循环之外工作? 【发布时间】:2011-02-07 16:09:48 【问题描述】:根据有关文件通配的 Perl 文档, 运算符或 glob() 函数在标量上下文中使用时,应遍历与指定模式匹配的文件列表,每次返回下一个文件名当没有更多文件时调用或 undef。
但是,迭代过程似乎只能在循环中进行。如果它不在循环中,那么它似乎在读取所有值之前立即重新开始。
来自 Perl 文档:
在标量上下文中,glob 遍历此类文件名扩展,当列表耗尽时返回 undef。
http://perldoc.perl.org/functions/glob.html
但是,在标量上下文中,运算符在每次调用时返回下一个值,或者在列表用完时返回 undef。
http://perldoc.perl.org/perlop.html#I/O-Operators
示例代码:
使用警告; 使用严格; 我的$文件名; # 在标量上下文中, 应该返回下一个文件名 # 每次调用它或当列表用完时取消定义 $文件名 = ; 打印“$文件名\n”; $文件名 = ; # 不像记录的那样工作,重新开始 打印“$文件名\n”; # 总是返回相同的文件名 $文件名 = ; 打印“$文件名\n”; 打印“\n”; print "$filename\n" while $filename = ; # 循环工作,返回下一个文件 # 每次调用在一个包含 3 个文件的目录中...file1.txt、file2.txt 和 file3.txt,上面的代码将输出:
文件1.txt 文件1.txt 文件1.txt 文件1.txt 文件2.txt 文件 3.txt注意:实际的 perl 脚本应该在 test 目录之外,否则您也会在输出中看到脚本的文件名。
我在这里做错了什么,还是它应该是这样工作的?
【问题讨论】:
【参考方案1】:这是一种将<>
glob 运算符状态的魔力捕获到一个对象中的方法,您可以通过一种正常的方式对其进行操作:匿名 subs(和/或闭包)!
sub all_files
return sub scalar <*> ;
my $iter = all_files();
print $iter->(), "\n";
print $iter->(), "\n";
print $iter->(), "\n";
或许:
sub dir_iterator
my $dir = shift;
return sub scalar glob("$dir/*") ;
my $iter = dir_iterator("/etc");
print $iter->(), "\n";
print $iter->(), "\n";
print $iter->(), "\n";
然后我的倾向是在“好奇心”下提交这个文件。忽略glob()
/ <>
这个特殊的奇怪之处,并使用opendir
/readdir
、IO::All/readdir
或File::Glob 代替:)
【讨论】:
捕获操作员状态的有趣方法和很好的解决方法。我想知道如何/是否可以做到。【参考方案2】:以下代码似乎还创建了 2 个独立的迭代器实例...
对于 ( 1..3 ) $文件名 = ; 如果已定义 $filename,则打印 "$filename\n"; $文件名 = ; 如果已定义 $filename,则打印 "$filename\n";我想我看到了那里的逻辑,但这有点违反直觉并且与文档相矛盾。文档没有提到任何关于必须在循环中才能使迭代工作的内容。
【讨论】:
+1 很棒的实验。这类似于范围运算符 (..
) 的行为方式,其中运算符的每次使用都保持自己的状态。哎呀,如果我能在任何地方找到记录的话。【参考方案3】:
同样来自perlop
:
(文件)glob 仅在开始新列表时评估其(嵌入)参数。
调用glob
会创建一个列表,该列表要么全部返回(在列表上下文中),要么一次检索一个元素(在标量上下文中)。但是每次调用glob
都会创建一个单独的列表。
【讨论】:
【参考方案4】:(擦掉我对 Perl 的生疏记忆...)我认为 <*>
的多个词法实例被视为 glob 的独立调用,而在 while 循环中,您调用的是相同的“实例”(无论是什么意思)。
想象一下,例如,如果你这样做:
while (<*>) ...
...
while (<*>) ...
您当然不会期望这两个调用会相互干扰。
【讨论】:
根据文档,它们不会干扰,因为第一次调用会在返回 undef 后重置。 我希望在不同的范围内有单独的实例,但在同一个范围内我希望调用相同的“实例”。 如果第一个中间有条件“break”怎么办?归根结底,Perl 解释器实际上所做的是“真相”。 在循环之外,有没有办法再次调用第一个“实例”? @Rob,不,它是 optree 中的东西,而不是普通 perl 意义上的“对象”。没有实用的方法来解决它。我想我知道一种方法来具体化它——答案即将到来:)以上是关于为啥 Perl 文件 glob() 不能在标量上下文中的循环之外工作?的主要内容,如果未能解决你的问题,请参考以下文章