在 Perl 中,为什么 `while() {...}` 构造不本地化 `$_`?

发布于 2024-10-28 13:01:53 字数 1019 浏览 1 评论 0原文

Perl 不使用以下语法自动本地化 $_ 的设计(或技术)原因是什么:

while (<HANDLE>) {...}

它被重写为:

while (defined( $_ = <HANDLE> )) {...}

隐式写入 $_ 的所有其他构造> 以本地化方式(for/foreachmapgrep)执行此操作,但使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心欲静而疯不止 2024-11-04 13:01:53

来自 perlmonks.org 上的线程

foreach之间有区别
while 因为它们完全是两个
不同的事情。 foreach 总是
循环时分配给变量
在列表上, while while 通常
没有。只是 while (<>)
一个例外,并且只有当有一个
单钻石运营商有一个
隐式赋值给 $_

还有:

while(<>)的一个可能原因
不会将 $_ 隐式本地化为
它的神奇之处在于有时
您想要访问的最后一个值
$_ 位于循环之外。

From the thread on perlmonks.org:

There is a difference between foreach
and while because they are two totally
different things. foreach always
assigns to a variable when looping
over a list, while while normally
doesn't. It's just that while (<>) is
an exception and only when there's a
single diamond operator there's an
implicit assignment to $_.

And also:

One possible reason for why while(<>)
does not implicitly localize $_ as
part of its magic is that sometimes
you want to access the last value of
$_ outside the loop.

初与友歌 2024-11-04 13:01:53

很简单,while 永远不会本地化。没有变量与 while 构造相关联,因此它甚至没有任何需要本地化的内容。

如果您更改 while 循环表达式或 while 循环体中的某些变量,则您有责任充分确定其范围。

Quite simply, while never localises. No variable is associated with a while construct, so it doesn't have even have anything to localise.

If you change some variable in the while loop expression or in a while loop body, it's your responsibility to adequately scope it.

无语# 2024-11-04 13:01:53

推测:因为 forforeach 是迭代器并循环值,而 while 对条件进行操作。在 while () 的情况下,条件是从文件中读取数据。 是写入 $_ 的内容,而不是 while。隐式 define() 测试只是一种功能,可以防止天真的代码在读取错误值时终止循环。

对于其他形式的 while 循环,例如 while (/foo/),您不会想要本地化 $_

虽然我同意如果 while () 本地化 $_ 会很好,但这必须是一个非常特殊的情况,这可能会导致其他问题识别何时触发和何时不触发,就像 的规则区分是句柄读取还是对 glob 的调用。

Speculation: Because for and foreach are iterators and loop over values, while while operates on a condition. In the case of while (<FH>) the condition is that data was read from the file. The <FH> is what writes to $_, not the while. The implicit defined() 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 to glob.

转角预定愛 2024-11-04 13:01:53

附带说明一下,我们只编写 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 for while(<$fh>) or the special cases associated with it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文