为什么 print() 不受运算符优先级的影响?

Whi*_*ist 1 perl parsing side-effects operators

当我在测试中获得一个奇怪的结果时,我正在为 C 制作一个运算符优先级和结合性表,对于 Perl 来说,这是同样奇怪的先验行为。

**运算符是右关联的,这意味着表达式是从右到左计算的。

显然,它可以正确地处理算术表达式,但奇怪的是,它不会通过打印函数调用产生预期的结果。

我期望这个输出321

$ perl -E 'print("1") ** print("2") ** print("3"); say ""'
123
Run Code Online (Sandbox Code Playgroud)

但它产生123

用户定义的函数也会发生这种情况:

$ perl -E 'sub my_print { print $_[0] } my_print(1) ** my_print(2) ** my_print(3); say ""'
123
Run Code Online (Sandbox Code Playgroud)

更奇怪的是,

$ perl -E 'sub my_print { say $_[0]; $_[0] } say my_print(2) ** my_print(2) ** my_print(4);'
2
2
4
65536
Run Code Online (Sandbox Code Playgroud)

当我们定义一个有副作用的函数时print,它也会返回一个值。算术表达式的结果具有正确的期望值,并且按照运算符结合性定义的顺序进行求值,但print仍然不符合运算符结合性。

就好像有两个评估顺序。

  • 正常的评估顺序,由 AST 和对其进行评估的算法定义(或更可能在man perlguts和中解释的“评估顺序传递”期间op.c)。
  • 副作用或 I/O 的第二个评估顺序,似乎具有副作用的内置函数调用被放入队列中,这带来了问题:它们按什么顺序放置

我假设这不是一个错误,而是一个功能。如果这是一个错误,那么它早就被发现了。

所以这给我带来了实际的问题: 这种行为的合理性是什么? 以及 它是如何实施的?。(意味着使用哪些数据结构以及在哪个编译时间阶段发生这种情况)。

如果我认为某处存在 AST 级别队列是对的,那么调用按什么顺序排队print

EDIT1: 作为额外的精度,我知道 I/O 期间涉及队列,但这并没有改变 I/O 操作通常按程序的评估顺序排队的事实,而不是任意从左到右的顺序程序文本的正确顺序。

ike*_*ami 8

您混淆了操作数求值顺序和运算符优先级/关联性。


运算符结合性决定了如果

X ** Y ** Z          // 2 ** 2 ** 3, for example
Run Code Online (Sandbox Code Playgroud)

方法

( X ** Y ) ** Z      // ( 2 ** 2 ) ** 3 = 64
Run Code Online (Sandbox Code Playgroud)

或者

X ** ( Y ** Z )      // 2 ** ( 2 ** 3 ) = 256
Run Code Online (Sandbox Code Playgroud)

正如您提到的,**是右结合的,所以它意味着后者。

X它与、YZY ** Z相对于彼此求值的顺序无关。只要 和YZ之前求值Y ** Z,无论这四个表达式的计算顺序如何,上面的结果都会产生相同的结果。

可以得出一些结论。如前所述,Y显然Z需要先进行评估Y ** Z。但是如果没有这样的要求[1] ,并且文档[2]中没有明确的相反声明,则可以按照编译器选择的顺序对运算符进行评估。


  1. 另一个例子是短路运算符必须先评估其左侧操作数,然后再评估其右侧操作数。

  2. 逗号运算符保证按顺序计算每个操作数。