2012-03-08 42 views
3

一边看书先进的Perl编程[1],我碰到 来到这个代码:使用与文件句柄定义和while循环

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

是否有使用这里任何defined特殊原因?对于 perlop得到文档说:

在这些循环结构,所分配的值(指配是否是 自动或显式)然后进行测试以查看它是否被定义。定义的 定义的测试避免了行中有一个字符串值012xx被Perl视为错误的问题,例如"""0"而没有尾随 换行符。如果你真的是这样的值,以终止循环,它们 应该是明确的测试:[...]

因此,会有一个角落的情况下,或者是仅仅是因为这本书太旧 和在最近的Perl版本中添加了自动defined测试?


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

回答

7

Perl有很多隐式行为,比其他大多数语言都多。 Perl的座右铭是“有更多的事情需要去做”,而且由于有太多隐含的行为,通常有多种方式来表达完全相同的东西。

/foo/,而不是$_ =~ m/foo/

$x = shift$x = shift @_

while (defined($_=<ARGV>))而不是while(<>)

,而不是等

要使用的表情在很大程度上是你的LOCA的问题l编码标准和个人喜好。更明确的表达方式会提醒读者引擎盖下的真实情况。这可能会也可能不会提高代码的可读性 - 这取决于观众的知识水平以及您是否使用了众所周知的习惯用法。

在这种情况下,隐式行为比看起来稍微复杂一些。有时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

的输出我还注意到,对实际问题的回答埋在最后一段。 – darch 2012-03-08 18:07:31

+0

当'/ foo /'表示'$ _ =〜/ foo /'时,非常明显,但当<>表示'defined defined($ _ = <>)'时,就不那么清楚了。我不认为他们是一样的。 – ikegami 2012-03-08 21:05:06

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

尝试用去除定义的代码,你会看到不同的结果。

+0

我知道这将是不同的,但事实并非如此。问题是关于在循环条件中使用'defined'。 – sidyll 2012-03-08 16:58:20

+1

-1,每个人不回答问题并提供非编译代码。 – darch 2012-03-08 18:06:18

+0

Perl用'while(自定义($ line = ))'自动替换'while($ line = )',所以如果你看到不同的东西,你明显在谈论与OP不同的东西。 (请参阅'perl -MO = Deparse -e'while('line = ){}'') – ikegami 2012-03-08 20:49:23

2

假设你有以下文件

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 (define($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