我正在阅读“Programming Perl“,遇到了一个奇怪的例子,似乎没有意义。这本书描述了Perl中的逗号操作符在标量上下文中使用时如何只返回最后一个结果。
范例:
# After this statement, $stuff = "three"
$stuff = ("one", "two", "three");
书中然后在几页后给出了这个“反逗号运算符”的例子(第82页)
# A "reverse comma operator".
return (pop(@foo), pop(@foo))[0];
然而,对我来说,这似乎并不完全相反...?
范例:
# After this statement, $stuff = "three"
$stuff = reverse_comma("one", "two", "three");
# Implementation of the "reverse comma operator"
sub reverse_comma {
return (pop(@_), pop(@_))[0];
}
这怎么会与正常的逗号运算符相反呢?结果是一样的,而不是相反的!
- 这里是一个link到确切的页面。例子在底部附近。*
4条答案
按热度按时间svmlkihl1#
这是一个糟糕的例子,应该被忘记。
它所展示的很简单:
[0]
放在最后,它就会把这个序列变成一个列表,并取它的第一个元素,例如:出于某种原因,这本书称之为“反逗号运算符”。这是用词不当;它只是一个列表的第一个元素。
这本书在参数中使用了两次
pop
函数,这使问题变得更加混乱。这些函数是从左到右求值的,所以第一个pop
的求值结果是"three"
,第二个是"two"
。在任何情况下:不要在真实的代码中使用逗号或“反逗号”操作符。这两种操作符都可能会让未来的读者感到困惑。
vof42yt12#
这是一个可爱而聪明的例子,但是太过认真地思考它会分散你的注意力,因为这一部分是在炫耀列表切片,而除了切片之外的任何东西,无论列表中有什么,都与例子的目的无关。
你只读到了一本很大的书的第82页(因为绑定方法已经到了极限,我们真的无法再写更多的页了),所以我们也没有什么可以给你的了。在其他列表切片示例中,有一个很聪明的例子,我不会在真实的代码中使用。这就是人为示例的诅咒。
但假设有一个反向逗号运算符。它必须计算逗号的两边。许多答案都是正确的“只返回第一件事”。但这不是它的功能。即使你保留了一个表达式,你也必须访问每个表达式。
考虑一下这个高级得多的版本,它包含一系列匿名子例程,我立即取消引用这些子例程,每个子例程打印一些内容,然后返回一个结果:
因为赋值运算符比逗号运算符绑定得更紧,所以括号只是为了优先考虑。这里没有列表,尽管看起来有。
输出显示Perl对每个都进行了计算,尽管它保留了最后一个:
名称不正确的wantarray内置函数返回false,说明子例程认为它位于标量上下文中。
现在,假设你想把它翻转过来,这样它仍然对每个表达式求值,但保留第一个表达式。你可以使用一个文本列表访问:
添加订阅后,右边现在是一个列表,我取出第一项。注意,第二个子例程认为它现在处于列表上下文中。我得到第一个子例程的结果:
但是,让我们把它放在一个子例程中。我仍然需要调用每个子例程,即使我不会使用其他子例程的结果:
或者,我会使用其他表达式的结果吗?如果我做了一些稍微不同的事情会怎样?我会在计算出的表达式中添加设置
$last
的副作用:现在我看到了标量逗号的有趣之处,它可以计算所有的表达式,其中一些表达式可能会产生副作用:
tchrist对shell脚本得心应手,这并不是一个大秘密。Perl到csh的转换器基本上就是他的收件箱(或comp.lang.perl)。你会在他的例子中看到一些类似shell的习惯用法。比如用一条语句交换两个数值的技巧:
副作用很重要。
回到Camel,我们有一个例子,其中具有副作用的是pop数组运算符:
这表明所有逗号两边的每个表达式都被求值了。由于我们没有给出一个完整的例子,所以我在子例程 Package 器中抛出了这个函数:
但是,这些都不是该节的重点,该节是索引到列表文字中。该示例的重点不是返回与其他示例或Perl特性不同的结果。它是在假设逗号操作符的作用不同的情况下返回相同的结果。该节是关于列表切片的,并展示了列表切片,因此列表中的内容并不是重要的部分。
r6vfmomb3#
让我们让这些例子更加相似。
逗号运算符:
反向逗号运算符:
这是一个“反逗号”,因为
$scalar
得到第一个表达式的结果,而普通的逗号运算符给出最后一个表达式(如果你对Lisp有所了解,这就像progn
和prog1
之间的区别)。将“反逗号运算符”实现为子例程,如下所示:
yrwegjxp4#
普通逗号将计算其操作数,然后返回右侧操作数的值
将
$v
设置为$b
的值为了演示列表切片,Camel提出了一些代码,这些代码的行为类似于逗号运算符,但它计算其操作数,然后返回 * left * 操作数的值
类似的操作可以通过列表切片来完成,如下所示
它将
$v
设置为$a
的值这就是它的全部内容。这本书并没有试图建议应该有一个 reverse comma 子例程,它只是考虑了按顺序计算两个表达式并返回第一个表达式的问题。只有当两个表达式有副作用时,计算的顺序才是相关的,这就是为什么书中的示例使用
pop
,它改变数组并返回一个值想象中的问题是
假设我想要一个子例程删除数组的最后两个元素,然后返回最后一个元素的值
通常这需要一个临时变量,如下所示
但是,* 作为列表切片的示例 *,代码建议这也可以工作
请理解,这不是一个建议。有几种方法可以做到这一点。另一个单一语句的方法是
但它没有使用列表切片,而这正是本书这一节的主题。实际上,我怀疑本书的作者除了使用临时变量的简单解决方案之外,是否还会提出其他任何建议。
我希望这对你有帮助