为啥 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() / &lt;&gt; 这个特殊的奇怪之处,并使用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 的生疏记忆...)我认为 &lt;*&gt; 的多个词法实例被视为 glob 的独立调用,而在 while 循环中,您调用的是相同的“实例”(无论是什么意思)。

想象一下,例如,如果你这样做:

while (<*>)  ... 
...
while (<*>)  ... 

您当然不会期望这两个调用会相互干扰。

【讨论】:

根据文档,它们不会干扰,因为第一次调用会在返回 undef 后重置。 我希望在不同的范围内有单独的实例,但在同一个范围内我希望调用相同的“实例”。 如果第一个中间有条件“break”怎么办?归根结底,Perl 解释器实际上所做的是“真相”。 在循环之外,有没有办法再次调用第一个“实例”? @Rob,不,它是 optree 中的东西,而不是普通 perl 意义上的“对象”。没有实用的方法来解决它。我想我知道一种方法来具体化它——答案即将到来:)

以上是关于为啥 Perl 文件 glob() 不能在标量上下文中的循环之外工作?的主要内容,如果未能解决你的问题,请参考以下文章

在标量上下文中展平 Perl 数组的方法

为啥 Perl 使用空字符串来表示 boolean false 值?

Perl:标量,数组,哈希

Perl glob 在尝试匹配特定文件类型时返回误报

Perl语言学习,不要停哟~~

通过引用和标量变量传递 Perl 哈希