Perl 5.10+ 中词法 $_ 的优缺点
Posted
技术标签:
【中文标题】Perl 5.10+ 中词法 $_ 的优缺点【英文标题】:The good, the bad, and the ugly of lexical $_ in Perl 5.10+ 【发布时间】:2011-03-24 22:12:24 【问题描述】:从 Perl 5.10 开始,现在可以对上下文变量 $_
进行词法作用域,或者显式为 my $_;
或在 given / when
构造中。
有没有人发现 $_
的好用法?它是否使任何构造更简单/更安全/更快?
如果情况变得更复杂怎么办?词汇$_
是否在您的代码中引入了任何错误? (因为写入$_
的控制结构将使用词法版本,如果它在范围内,如果它包含任何子例程调用(由于失去动态范围),这可以改变代码的行为)
最后,我想构建一个列表,阐明何时将$_
用作词法、全局或什么时候根本不重要。
注意:截至perl5-5.24
,这些实验性功能为no longer part of perl。
【问题讨论】:
我认为你的问题的答案大部分都包含在我的问题的答案中here。 @xenoterracide => 那里的答案肯定涵盖了词汇$_
的某些方面,但不是全部。这就是我想在这里介绍的内容。
我知道,但最好有一个开始的好地方;)
好问题。我会+1,但我的选票用完了。 :)
【参考方案1】:
IMO,词法 $_
带来的一件好事是新的 _
原型符号。
这允许您指定一个子例程,以便它采用一个标量,或者如果没有提供,它将获取$_
。
所以不要写:
sub foo
my $arg = @_ ? shift : $_;
# Do stuff with $_
我会写:
sub foo(_)
my $arg = shift;
# Do stuff with $_ or first arg.
变化不大,但当我想要这种行为时,它就简单多了。去除样板是一件好事。
当然,这会产生改变几个内置函数原型的连锁反应(例如chr
),这可能会破坏一些代码。
总的来说,我欢迎词法$_
。它给了我一个工具,我可以用它来限制意外的数据修改和函数之间的奇怪交互。如果我决定在函数体中使用$_
,通过词法化它,我可以确定无论我调用什么代码,$_
在调用代码中都不会被修改。
动态范围很有趣,但在大多数情况下,我想要词法范围。再加上$_
周围的复杂情况。我听说过关于简单地做local $_;
不明智的可怕警告——最好改用for ( $foo )
。当我以任何方式本地化$_
时,词汇化的$_
给了我100 次中的99 次我想要的东西。词法$_
使一个非常方便和可读性更强大的功能。
我的大部分工作都必须使用 perl 5.8,因此我没有在大型项目中使用词汇 $_
的乐趣。但是,感觉这将大大有助于使$_
的使用更安全,这是一件好事。
【讨论】:
给出了for ($foo) ...
而不是local *_ = \$foo;
的原因是什么?根据我的经验,后者要快一些(因为它不必为单个元素列表设置范围和迭代器),但如果有任何安全问题需要牢记,我会很感兴趣。
Eric,我今天去找了具体的参考,没找到。在这一点上,我所能记得的只是对local $_
的警告,该警告来自 2009 年年中某个时候来自“我尊重其意见的人”。因此,除非我能更好地证实这一说法,否则最好将其视为道听途说。声称是本地化并没有涵盖具有公认特殊$_
的所有边缘情况。我从来没有找到错误报告或测试用例来支持警告。【参考方案2】:
我曾经在玩Inline
模块时发现了一个issue(这个词太强了)。这个简单的脚本:
use strict qw(vars subs);
for ('function')
$_->();
sub function
require Inline;
Inline->bind(C => <<'__CODE__');
void foo()
__CODE__
失败并显示Modification of a read-only value attempted at /usr/lib/perl5/site_perl/5.10/Inline/C.pm line 380.
错误消息。在Inline
模块的内部深处是一个想要修改$_
的子程序,导致上面的错误消息。
使用
for my $_ ('function') ...
或以其他方式声明 my $_
是解决此问题的可行解决方法。
(Inline
模块已修补以修复此特定问题)。
【讨论】:
【参考方案3】:[ 基本原理: 一个简短的附加答案,为可能路过的 perl 新手提供快速总结。当搜索“perl lexical topic”时,可以在这里结束。]
到现在(2015 年),我想众所周知,词汇主题(my $_
和一些相关功能)的引入会在一开始就导致一些难以检测的意外行为,marked 和 experimental 也是如此然后输入了deprecation stage。
部分摘要
#RT119315
: 一个建议是use feature 'lextopic';
to make use of a new lexical topic variable:$^_
。 另一点是“implicit name for the topicalizing operator ... other than$_
”在与明确的词法函数(例如词法map
或lmap
)结合使用时效果最好。这些方法是否能以某种方式挽救given/when
尚不清楚。在实验和折旧阶段的来世,也许某些东西最终可能会继续存在于 CPAN 的河流中。
【讨论】:
【参考方案4】:在这里没有遇到任何问题,尽管在谈到 Perls 魔法时,我倾向于遵循某种“不问,不说”的政策。 IE。例程通常不希望依赖于他们的同行将非词汇数据作为副作用,也不会让他们。
我已经针对各种 5.8 和 5.10 版本的 perl 测试了代码,同时使用 5.6 描述 Camel 作为偶尔参考。没有遇到任何问题。我的大部分东西最初都是为 perl 5.8.8 完成的。
【讨论】:
以上是关于Perl 5.10+ 中词法 $_ 的优缺点的主要内容,如果未能解决你的问题,请参考以下文章
[Perl] 在 perl 5.10 中读取带分隔符的文本文件并插入到 mysql 表中
在linux下的如何将perl默认版本5.8.8升级为5.10