Perl 中逗号运算符的执行顺序
考虑以下脚本:
print'+'x$z,($z=1,$w)?'':$_ for 1..3;
正如我所期望的,它会打印 1+2+3
。变量 $z
最初未分配,因此 '+'x$z
计算结果为空;之后,$z
设置为 1,因此 '+'x$z
现在的计算结果为 +
。
但是,如果我更改此设置以使 $z
包含 +
本身:
print$z,($z='+',$w)?'':$_ for 1..3;
脚本现在会打印 +1+2+3
。这似乎表明执行顺序不同,但我不明白为什么。
导致这两个示例表现不同的执行顺序的确切规则是什么?执行顺序是否明确定义?
Consider the following script:
print'+'x$z,($z=1,$w)?'':$_ for 1..3;
This prints, as I would expect, 1+2+3
. The variable $z
is initially unassigned, so '+'x$z
evaluates to empty; after that, $z
is set to 1, so '+'x$z
now evaluates to +
.
However, if I change this so that $z
contains the +
itself:
print$z,($z='+',$w)?'':$_ for 1..3;
the script now prints +1+2+3
. This seems to suggest to me that the order of execution is different, but I don’t understand why.
What are the precise rules regarding order of execution that cause these two examples to behave differently? Is the order of execution even well-defined?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在 Perl 中参数通过引用传递。
基本上是
因为
$_[0]
是$z
的别名,所以对$z
的更改会反映在$_[0] 中
,即使这些更改发生在评估参数之后。您可以在下面看到相同的效果:
Arguments are passed by reference in Perl.
is basically
Because
$_[0]
is aliased to$z
, changes to$z
are reflected in$_[0]
, even if those changes occur after the argument is evaluated.You can see the same effect in the following:
这是我试图理解你的两个例子。考虑这个脚本:
输出,带有一些注释:
在版本 1 中,Perl 无法将
$z + 2
直接传递给dd()
。它必须评估表达式。该评估的结果(常量 2)作为第一个参数传递。第二个参数也被计算:$z
设置为 1,赋值的返回值为$z
,然后$z
为通过引用dd()
传递。在版本 2 中,Perl 可以简单地通过引用直接传递第一个参数:无需计算更大的表达式。第二个参数与版本 1 中的相同。结果是
dd()
接收相同的变量两次,如Data::Dumper
输出所示。Here's my attempt to make sense of your two examples. Consider this script:
The output, with some comments:
In Version 1, Perl cannot pass
$z + 2
directly todd()
. It must evaluate the expression. The result of that evaluation (the constant 2) is passed as the first argument. The second argument is also evaluated:$z
is set to 1, the return value of the assignment is$z
, and then$z
is passed by reference todd()
.In Version 2, Perl can simply pass the first argument directly by reference: no need to evaluate a larger expression. The second argument is the same as in Version 1. The result is that
dd()
receives same variable twice, as shown in theData::Dumper
output.原始答案
您需要通过
perl -MO=Deparse,-p
运行它。第一段代码显示了这一点:但第二段代码显示了这一点:
显然
,这显然不足以向某些人充分解释问题。不应该是这样,因为我原以为这是很清楚的。
接受的解决方案错误地指出,这在某种程度上与 Perl 通过隐式引用传递标量变量的事实有关。与此完全无关。这是一个简单的优先级和评估顺序问题。我本来希望 Deparse 输出能够清楚地表明这一点。
显然有些人仍然感到困惑。
第一个版本
很好,这是为您精心准备的解释。
这:
由 Deparse 和一些额外的格式提供,与此等效:
现在,展开循环并分离出产生以下内容时发生的情况:
所有三个都会产生相同的输出:
1+2+3
。第二个版本
现在我们再次从原始版本开始:
并生成一个解析版本:
然后是一个循环展开版本:
所有三个版本,出于我真正希望现在非常清楚的原因,打印相同的结果:<代码>+1+2+3。
为了进一步的启发,
追踪正在发生的事情的最好方法是在它上面留下痕迹:
当你运行它时,它会产生这个相当令人满意的输出:
总结
我现在已经费力地证明了这里实际发生的事情是无事可做的通过引用传递。它只与评估的顺序有关,与其他无关。
The Original Answer
You need to run this through
perl -MO=Deparse,-p
. The first bit of code shows this:But the second bit of code shows this:
Confusticated and Bebothered
Apparently that proved insufficient to sufficiently explain matters to some people. It was not supposed to be, for I had thought it perfectly clear.
The accepted solution erroneously states that this somehow has something to do with the fact that Perl passes scalar variables by implicit reference. It has nothing to with that at all. It is a simple matter of precedence and order of evaluation. I had intended that the Deparse output should make that clear.
Apparently some are still confused.
The First Version
Very well, here’s your explanation all daintied up on silver platter for you.
This:
is equivalent, courtesy of Deparse and some extra formating, to this:
Now, unrolling the loop and separating out what happens when produces this:
All three of those produce identical output:
1+2+3
.The Second Version
Now we start again with the original:
and produce a deparsing version:
followed by a loop unroll version:
All three versions, for reasons I REALLY HOPE ARE NOW ABUNDANTLY CLEAR print the same result:
+1+2+3
.For Further Enlightenment
The best way to track down what is happening when is to put a trace on it:
When you run that, it produces this rather gratifying output:
Summary
I have now laboriously demonstrated that what is actually happening here as nothing whatsoever to do with pass-by-reference. It has to do with only the order of evaluation alone, and nothing else.