用Filehandle和while循环定义的用法

时间:2012-03-08 16:33:04

标签: perl while-loop filehandle

在阅读有关高级Perl编程(1)的书时,我遇到了 这段代码:

while (defined($s = <>)) {
    ...

在这里使用defined有什么特殊原因吗? documentation for perlop说:

  

在这些循环结构中,赋值(无论赋值是否为   然后测试自动或显式)以查看它是否已定义。该   定义的测试避免了line具有字符串值的问题   被Perl视为false,例如"""0"没有尾随   新队。如果你真的想要这些值来终止循环,那么它们   应该明确地进行测试:[...]

那么,是否会有一个角落案件,或仅仅是因为这本书太旧了 并且在最近的Perl版本中添加了自动defined测试?


(1)高级Perl编程,第一版,Sriram Srinivasan。奥赖利 (1997)

3 个答案:

答案 0 :(得分:8)

Perl有很多隐式行为,比其他大多数语言都多。 Perl的座右铭是有不止一个要做的事情,并且因为有太多的隐含行为,通常有多种方式来表达完全相同的事情。

  

/foo/代替$_ =~ m/foo/

     

$x = shift代替$x = shift @_

     

while (defined($_=<ARGV>))代替while(<>)

     

使用哪种表达方式主要取决于您当地的编码标准和个人偏好。更明确的表达提醒读者在幕后真正发生了什么。这可能会也可能不会提高代码的可读性 - 这取决于受众的知识水平以及您是否使用了众所周知的习语。

在这种情况下,隐式行为比看起来要复杂一些。有时perl会隐式对readline运算符的结果执行defined(...)测试:

$ perl -MO=Deparse -e 'while($s=<>) { print $s }'
while (defined($s = <ARGV>)) {
    print $s;
}
-e syntax OK

但有时它不会:

$ perl -MO=Deparse -e 'if($s=<>) { print $s }'
if ($s = <ARGV>) {
    print $s;
}
-e syntax OK

$ perl -MO=Deparse -e 'while(some_condition() && ($s=<>)) { print $s }'
while (some_condition() and $s = <ARGV>) {
    print $s;
}
-e syntax OK

假设您担心此隐式行为应该处理的极端情况。您是否已将perlop提交给内存,以便了解Perl何时使用此隐式行为以及何时不使用此行为?您是否了解Perl v5.14与Perl v5.6之间在此行为上的差异?阅读代码的人会理解吗?

同样,关于何时使用更明确的表达式没有正确或错误的答案,但是当隐式行为更深奥时,使用显式表达式的情况更强。

答案 1 :(得分:3)

假设您有以下文件

4<LF>
3<LF>
2<LF>
1<LF>
0

<LF>表示换行。请注意最后一行缺少换行符。)

假设您使用代码

while ($s = <>) {
   chomp;
   say $s;
}

如果Perl没有做任何神奇的事情,那么输出就是

4
3
2
1

请注意缺少0,因为字符串0为false。

在不太可能的情况下需要defined
  • 您有一个非标准的文本文件(缺少尾随换行符)。
  • 文件的最后一行包含一个ASCII零(0x30)。

但是等一下!如果您实际使用上述数据运行上述代码,您会看到0已打印出来!许多人不知道的是Perl会自动翻译

while ($s = <>) {

while (defined($s = <>)) {

如图所示:

$ perl -MO=Deparse -e'while($s=<DATA>) {}'
while (defined($s = <DATA>)) {
    ();
}
__DATA__
-e syntax OK

因此,从技术上讲,您甚至不需要在这种非常具体的情况下指定defined

那就是说,我不能责怪某人是明确的,而不是依赖于Perl自动修改他们的代码。毕竟,Perl(必然)非常具体地说明它将改变哪些代码序列。请注意,以下缺少defined,即使它应该是等效的代码:

$ perl -MO=Deparse -e'while((), $s=<DATA>) {}'
while ((), $s = <DATA>) {
    ();
}
__DATA__
-e syntax OK

答案 2 :(得分:-2)

while($line=<DATA>){
    chomp($line);
if(***defined*** $line){
    print "SEE:$line\n";
}
}
__DATA__
1
0
3

尝试删除已定义的代码,您将看到不同的结果。