Perl - 列表元素的评估顺序,在列表内分配
Perl - evaluation order of list elements, with assignment inside the list
根据 Perldoc(https://perldoc.perl.org/perlop#Comma-Operator):
Comma Operator
...
In list context, it's just the list argument separator, and inserts both its arguments into the list. These arguments are also evaluated from left to right.
在下面的代码中,我认为 $n
应该是 1
但它变成了 2
。我错过了什么?
my $v = 1;
my $n = ( $v, $v = 2 )[0];
# I thought left "$v" would be evaluated (and return 1) first, then right "$v = 2" would.
say "n = $n"; # but output was 2
say "v = $v"; # 2
或
my $v = 1;
my @l = ( $v, $v = 2 );
say Dumper(\@l); # [ 2, 2 ], not [ 1, 2 ]
即使我更改了顺序:
my $v = 1;
# my $n = ( $v, $v = 2 )[0];
my $n = ( $v = 2, $v )[1];
say "n = $n"; # still 2
say "v = $v"; # 2
它确实是从左到右计算的。
$ perl -MO=Concise,-exec -e'my $v = 1; my $n = ( $v, $v = 2 )[0];'
1 <0> enter v
2 <;> nextstate(main 1 -e:1) v:{
3 <$> const[IV 1] s \
4 <0> padsv[$v:1,3] sRM*/LVINTRO > my $v = 1;
5 <2> sassign vKS/2 /
6 <;> nextstate(main 2 -e:1) v:{
7 <0> pushmark s \ \
8 <$> const[IV 0] s | |
9 <0> pushmark s | |
a <0> padsv[$v:1,3] s $v > ( ... )[0] |
b <$> const[IV 2] s \ | > my $n = ...
c <0> padsv[$v:1,3] sRM* > $v = 2 | |
d <2> sassign sKS/2 / | |
e <2> lslice sK/2 / |
f <0> padsv[$n:2,3] sRM*/LVINTRO |
g <2> sassign vKS/2 /
h <@> leave[1 ref] vKP/REFC
-e syntax OK
要注意的是,与 $v
关联的标量放在堆栈上,而不是整数。你可以在这里看到发生了什么:
use 5.014;
use warnings;
my @stack;
sub sassign {
my $rhs = pop(@stack);
my $lhs = pop(@stack);
$$rhs = $$lhs;
push @stack, $rhs;
}
# Stack $v $n
# ------- -- --
push @stack, ; # 1
push @stack, \my $v; # 1,$v !d
sassign(); # $v 1
@stack = (); # 1
push @stack, $v; # $v 1
push @stack, ; # $v,2 1
push @stack, $v; # $v,2,$v 1
sassign(); # $v,$v 2
pop(@stack); # $v 2 # Net result of slice.
push @stack, \my $n; # $v,$n 2 !d
sassign(); # $n 2 2
@stack = (); # 2 2
say $n; # 2
如果您更喜欢别名而不是引用:
use 5.014;
use warnings;
use experimental qw( refaliasing declared_refs );
my @stack;
sub sassign {
my $rhs = \pop(@stack);
my $lhs = \pop(@stack);
$rhs = $lhs;
$stack[@stack] = $rhs;
}
# Stack $v $n
# ------- -- --
$stack[@stack] = ; # 1
$stack[@stack] = \my $v; # 1,$v !d
sassign(); # $v 1
@stack = (); # 1
$stack[@stack] = $v; # $v 1
$stack[@stack] = ; # $v,2 1
$stack[@stack] = $v; # $v,2,$v 1
sassign(); # $v,$v 2
pop(@stack); # $v 2 # Net result of slice.
$stack[@stack] = \my $n; # $v,$n 2 !d
sassign(); # $n 2 2
@stack = (); # 2 2
say $n; # 2
根据 Perldoc(https://perldoc.perl.org/perlop#Comma-Operator):
Comma Operator
...
In list context, it's just the list argument separator, and inserts both its arguments into the list. These arguments are also evaluated from left to right.
在下面的代码中,我认为 $n
应该是 1
但它变成了 2
。我错过了什么?
my $v = 1;
my $n = ( $v, $v = 2 )[0];
# I thought left "$v" would be evaluated (and return 1) first, then right "$v = 2" would.
say "n = $n"; # but output was 2
say "v = $v"; # 2
或
my $v = 1;
my @l = ( $v, $v = 2 );
say Dumper(\@l); # [ 2, 2 ], not [ 1, 2 ]
即使我更改了顺序:
my $v = 1;
# my $n = ( $v, $v = 2 )[0];
my $n = ( $v = 2, $v )[1];
say "n = $n"; # still 2
say "v = $v"; # 2
它确实是从左到右计算的。
$ perl -MO=Concise,-exec -e'my $v = 1; my $n = ( $v, $v = 2 )[0];'
1 <0> enter v
2 <;> nextstate(main 1 -e:1) v:{
3 <$> const[IV 1] s \
4 <0> padsv[$v:1,3] sRM*/LVINTRO > my $v = 1;
5 <2> sassign vKS/2 /
6 <;> nextstate(main 2 -e:1) v:{
7 <0> pushmark s \ \
8 <$> const[IV 0] s | |
9 <0> pushmark s | |
a <0> padsv[$v:1,3] s $v > ( ... )[0] |
b <$> const[IV 2] s \ | > my $n = ...
c <0> padsv[$v:1,3] sRM* > $v = 2 | |
d <2> sassign sKS/2 / | |
e <2> lslice sK/2 / |
f <0> padsv[$n:2,3] sRM*/LVINTRO |
g <2> sassign vKS/2 /
h <@> leave[1 ref] vKP/REFC
-e syntax OK
要注意的是,与 $v
关联的标量放在堆栈上,而不是整数。你可以在这里看到发生了什么:
use 5.014;
use warnings;
my @stack;
sub sassign {
my $rhs = pop(@stack);
my $lhs = pop(@stack);
$$rhs = $$lhs;
push @stack, $rhs;
}
# Stack $v $n
# ------- -- --
push @stack, ; # 1
push @stack, \my $v; # 1,$v !d
sassign(); # $v 1
@stack = (); # 1
push @stack, $v; # $v 1
push @stack, ; # $v,2 1
push @stack, $v; # $v,2,$v 1
sassign(); # $v,$v 2
pop(@stack); # $v 2 # Net result of slice.
push @stack, \my $n; # $v,$n 2 !d
sassign(); # $n 2 2
@stack = (); # 2 2
say $n; # 2
如果您更喜欢别名而不是引用:
use 5.014;
use warnings;
use experimental qw( refaliasing declared_refs );
my @stack;
sub sassign {
my $rhs = \pop(@stack);
my $lhs = \pop(@stack);
$rhs = $lhs;
$stack[@stack] = $rhs;
}
# Stack $v $n
# ------- -- --
$stack[@stack] = ; # 1
$stack[@stack] = \my $v; # 1,$v !d
sassign(); # $v 1
@stack = (); # 1
$stack[@stack] = $v; # $v 1
$stack[@stack] = ; # $v,2 1
$stack[@stack] = $v; # $v,2,$v 1
sassign(); # $v,$v 2
pop(@stack); # $v 2 # Net result of slice.
$stack[@stack] = \my $n; # $v,$n 2 !d
sassign(); # $n 2 2
@stack = (); # 2 2
say $n; # 2