为什么表达结果不同?

Eug*_*kov 1 perl operator-precedence

执行perl程序我得到不同的结果:

$ perl -e 'my $i = 2; $i += 2 + $i++; print "$i\n"'
7
$ perl -e 'my $i = 2; $i += $i + $i++; print "$i\n"'
8
Run Code Online (Sandbox Code Playgroud)

为什么结果不同?在第二种情况下我错过了什么?我希望7在这两种情况下.

ike*_*ami 6

对于您发布的任何一个片段,Perl不保证任何特定结果,您应该避免使用此类代码.


也就是说,所有现有的Perl构建的行为都是一致的.

虽然没有记录或保证,但Perl总是在右侧(RHS)之前评估加法运算符的左侧(LHS).[1]

$ perl -MO=Concise,-exec -e 'my $i = 2; $i += $i + $i++; print "$i\n"'
...
8  <0> padsv[$i:1,2] s       > LHS
9  <0> padsv[$i:1,2] sRM     \ RHS
a  <1> postinc[t2] sK/1      /
b  <2> add[t3] sK/2
...
Run Code Online (Sandbox Code Playgroud)

那么为什么看起来并非如此呢?

理解发生了什么的关键是Perl堆栈只包含标量(SV*包括诸如子类型AV*).这意味着$i将实际标量与$i堆栈相关联,而不仅仅是值2.[2]

这意味着即使$i在评估并放置在堆栈上之前$i++评估并放置在堆栈上,$i添加运算符也将使用更新后的值.

    $i  stack
    --  -----
     2
$i
     2  $i
$i
     2  $i,$i
postinc
     3  $i,2
add
     3  5
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以跟踪复制Perl解释器时发生的情况:

use Data::Alias qw( alias );

my @stack;
my @pad;

sub padsv {
   my $padidx = shift;
   alias push @stack, $pad[$padidx];
}

sub postinc {
   alias my $sv = pop(@stack);
   alias my $result = $sv++;
   alias push @stack, $result;
}

sub add {
   alias my ($lhs, $rhs) = splice(@stack, -2);
   alias my $result = $lhs + $rhs;
   alias push @stack, $result;
}


{ my $i = 2; say $i + $i++; }  # 5

$pad[0] = 2;
padsv(0); padsv(0); postinc(); add();
say pop(@stack);  # 5


{ my $i = 1; say $i + $i++ + $i++; }  # 5

$pad[0] = 1;
padsv(0); padsv(0); postinc(); add(); padsv(0); postinc(); add();
say pop(@stack);  # 5
Run Code Online (Sandbox Code Playgroud)

替代方案:

sub postinc :lvalue { $_[0]++ }
sub add :lvalue { $_[0] + $_[1] }

{ my $i = 2; say $i + $i++;            } # 5
{ my $i = 2; say add($i, postinc($i)); } # 5

{ my $i = 1; say $i + $i++ + $i++;                       } # 5
{ my $i = 1; say add(add($i, postinc($i)), postinc($i)); } # 5
Run Code Online (Sandbox Code Playgroud)
  1. 请注意,这与之前的答案相矛盾.它对发生的事情的解释是完全错误的并且被证明是错误的$i + $i++ + $i++.

  2. 这是出于性能原因而完成的.制作标量的副本是昂贵的,并且对堆放的每个标量这样做会对性能产生严重的负面影响.