在阅读有关高级Perl编程(1)的书时,我遇到了 这段代码:
while (defined($s = <>)) {
...
在这里使用defined
有什么特殊原因吗? documentation for
perlop说:
在这些循环结构中,赋值(无论赋值是否为 然后测试自动或显式)以查看它是否已定义。该 定义的测试避免了line具有字符串值的问题 被Perl视为false,例如
""
或"0"
没有尾随 新队。如果你真的想要这些值来终止循环,那么它们 应该明确地进行测试:[...]
那么,是否会有一个角落案件,或仅仅是因为这本书太旧了
并且在最近的Perl版本中添加了自动defined
测试?
(1)高级Perl编程,第一版,Sriram Srinivasan。奥赖利 (1997)
答案 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
但是等一下!如果您实际使用上述数据运行上述代码,您会看到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
尝试删除已定义的代码,您将看到不同的结果。