Perl如何决定在表达式中评估术语的顺序?

时间:2009-11-05 17:46:04

标签: perl operator-precedence associativity

鉴于代码:

my $x = 1;

$x = $x * 5 * ($x += 5);

我希望$x180

$x = $x * 5 * ($x += 5); #$x = 1
$x = $x * 5 * 6;         #$x = 6
$x = 30 * 6;
$x = 180;
180;

但它是30;但是,如果我改变术语的顺序:

$x = ($x += 5) * $x * 5;

我得到180。我感到困惑的原因是perldoc perlop非常清楚地说:

  

TERM在Perl中具有最高优先级。它们包括变量,   引用和引用类似的运算符,括号中的任何表达式,以及任何   参数为括号的函数。

由于($x += 5)在括号中,因此它应该是一个术语,因此首先执行,而不管表达式的顺序如何。

4 个答案:

答案 0 :(得分:16)

输入问题的行为给了我答案:条款具有最高优先权。这意味着评估第一个代码块中的$x并生成1,然后评估5并生成5,然后评估($x += 5)并且收益率6(带有将$x设置为6的副作用):

$x = $x * 5 * ($x += 5);
address of $x = $x * 5 * ($x += 5); #evaluate $x as an lvalue
address of $x = 1 * 5 * ($x += 5);  #evaluate $x as an rvalue
address of $x = 1 * 5 * ($x += 5);  #evaluate 5
address of $x = 1 * 5 * 6;          #evaluate ($x += 5), $x is now 6
address of $x = 1 * 5 * 6;          #evaluate 1 * 5
address of $x = 5 * 6;              #evaluate 1 * 5
address of $x = 30;                 #evaluate 5 * 6
30;                                 #evaluate address of $x = 30

同样,第二个例子如下所示:

$x = ($x += 5) * $x * 5; 
address of $x = ($x += 5) * $x * 5; #evaluate $x as an lvalue
address of $x = 6 * $x * 5;         #evaluate ($x += 5), $x is now 6
address of $x = 6 * 6 * 5;          #evaluate $x as an rvalue
address of $x = 6 * 6 * 5;          #evaluate 5
address of $x = 36 * 5;             #evaluate 6 * 6
address of $x = 180;                #evaluate 36 * 5
180;                                #evaluate $x = 180

答案 1 :(得分:9)

每当我对这样的东西感到困惑时,我首先拔出perldoc perlop,然后如果我仍然不确定,或者想看看特定的代码块是如何执行的,我会使用{{3 }}:

perl -MO=Deparse,-p,-q,-sC
my $x = 1;
$x = $x * 5 * ($x += 5);

^ d

给出:

(my $x = 1);
($x = (($x * 5) * ($x += 5)));
- syntax OK

因此,在每个阶段替换值会产生:

($x = (($x * 5) * ($x += 5)));
($x = ((1 * 5) * ($x += 5)));
($x = ((5) * (6))); # and side-effect: $x is now 6
($x = (5 * 6));
($x = (30));
($x = 30);
$x = 30;

因此,$ x暂时设置为6的事实并没有真正影响任何事情,因为较早的值(1)已经被替换为表达式,并且在表达式结束时它现在是30。

答案 2 :(得分:4)

$x本身也是一个术语。由于首先遇到它(在你的第一个例子中),它首先被评估。

答案 3 :(得分:2)

*运算符的关联性是向左的,因此最左边的术语总是在最右边的术语之前进行评估。其他运算符(例如**)是正确关联的,并且会在语句的其余部分之前评估($x += 5)