在 Perl 中,为什么 `while() {...}` 构造不本地化 `$_`?
Perl 不使用以下语法自动本地化 $_
的设计(或技术)原因是什么:
while (<HANDLE>) {...}
它被重写为:
while (defined( $_ = <HANDLE> )) {...}
隐式写入 $_
的所有其他构造> 以本地化方式(for/foreach
、map
、grep
)执行此操作,但使用 while
,您可以必须显式本地化变量:
local $_;
while (<HANDLE>) {...}
我的猜测是它与在“Super-AWK”模式下使用命令行开关使用 Perl 有关,但这可能是错误的。
因此,如果有人知道(或者更好的是参与了语言设计讨论),您能否与我们分享这种行为背后的原因?更具体地说,为什么允许 $_
的值在循环之外保留很重要,尽管它可能会导致错误(我倾向于在 SO 和其他 Perl 代码中看到这种错误) )?
如果上面的内容还不清楚,那么 $_
必须使用 while
进行本地化的原因如下例所示:
sub read_handle {
while (<HANDLE>) { ... }
}
for (1 .. 10) {
print "$_: \n"; # works, prints a number from 1 .. 10
read_handle;
print "done with $_\n"; # does not work, prints the last line read from
# HANDLE or undef if the file was finished
}
What was the design (or technical) reason for Perl not automatically localizing $_
with the following syntax:
while (<HANDLE>) {...}
Which gets rewritten as:
while (defined( $_ = <HANDLE> )) {...}
All of the other constructs that implicitly write to $_
do so in a localized manner (for/foreach
, map
, grep
), but with while
, you must explicitly localize the variable:
local $_;
while (<HANDLE>) {...}
My guess is that it has something to do with using Perl in "Super-AWK" mode with command line switches, but that might be wrong.
So if anyone knows (or better yet was involved in the language design discussion), could you share with us the reasoning behind this behavior? More specifically, why was allowing the value of $_
to persist outside of the loop deemed important, despite the bugs it can cause (which I tend to see all over the place on SO and in other Perl code)?
In case it is not clear from the above, the reason why $_
must be localized with while
is shown in this example:
sub read_handle {
while (<HANDLE>) { ... }
}
for (1 .. 10) {
print "$_: \n"; # works, prints a number from 1 .. 10
read_handle;
print "done with $_\n"; # does not work, prints the last line read from
# HANDLE or undef if the file was finished
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
来自 perlmonks.org 上的线程:
还有:
From the thread on perlmonks.org:
And also:
很简单,
while
永远不会本地化。没有变量与while
构造相关联,因此它甚至没有任何需要本地化的内容。如果您更改
while
循环表达式或while
循环体中的某些变量,则您有责任充分确定其范围。Quite simply,
while
never localises. No variable is associated with awhile
construct, so it doesn't have even have anything to localise.If you change some variable in the
while
loop expression or in awhile
loop body, it's your responsibility to adequately scope it.推测:因为
for
和foreach
是迭代器并循环值,而while
对条件进行操作。在while ()
的情况下,条件是从文件中读取数据。
是写入$_
的内容,而不是while
。隐式define()
测试只是一种功能,可以防止天真的代码在读取错误值时终止循环。对于其他形式的
while
循环,例如while (/foo/)
,您不会想要本地化$_
。虽然我同意如果
while ()
本地化$_
会很好,但这必须是一个非常特殊的情况,这可能会导致其他问题识别何时触发和何时不触发,就像
的规则区分是句柄读取还是对glob
的调用。Speculation: Because
for
andforeach
are iterators and loop over values, whilewhile
operates on a condition. In the case ofwhile (<FH>)
the condition is that data was read from the file. The<FH>
is what writes to$_
, not thewhile
. The implicitdefined()
test is just an affordance to prevent naive code from terminating the loop on a read of false value.For other forms of
while
loops, e.g.while (/foo/)
you wouldn't want to localize$_
.While I agree that it would be nice if
while (<FH>)
localized$_
, it would have to be a very special case, which could cause other problems with recognizing when to trigger it and when not to, much like the rules for<EXPR>
distinguishing being a handle read or a call toglob
.附带说明一下,我们只编写
while(<$fh>)
因为 Perl 没有真正的迭代器。如果 Perl 有适当的迭代器,<$fh>
将返回一个。for
将使用它一次迭代一行,而不是将整个文件放入数组中。不需要while(<$fh>)
或与之相关的特殊情况。As a side note, we only write
while(<$fh>)
because Perl doesn't have real iterators. If Perl had proper iterators,<$fh>
would return one.for
would use that to iterate a line at a time rather than slurping the whole file into an array. There would be no need forwhile(<$fh>)
or the special cases associated with it.