原始答案
您需要通过perl -MO=Deparse,-p
. 第一段代码显示了这一点:
print(('+' x $z), ((($z = 1), $w) ? '' : $_)) foreach (1 .. 3);
但是第二段代码显示了这一点:
print($z, ((($z = '+'), $w) ? '' : $_)) foreach (1 .. 3);
困惑和困扰
显然,这不足以向某些人充分解释问题。它不应该是,因为我认为它非常清楚。
公认的解决方案错误地指出,这在某种程度上与 Perl 通过隐式引用传递标量变量这一事实有关。它与那一点关系都没有。这是一个简单的优先级和评估顺序问题。我原本打算让 Deparse 输出清楚地说明这一点。
显然有些人仍然感到困惑。
第一个版本
很好,这是您的解释,所有这些都在银盘上为您精心准备。
这个:
print'+'x$z,($z=1,$w)?'':$_ for 1..3;
是等价的,由 Deparse 和一些额外的格式提供,到这个:
{
($w, $z) = (undef, undef);
for (1..3) {
print(("+" x $z), ((($z = 1), $w) ? "" : $_))
}
} continue {
print "\n";
}
现在,展开循环并分离出产生以下内容时发生的情况:
{
($w, $z) = (undef, undef);
{
local $_ = 1;
$temp = "+" x $z; # $z is undef
$z = 1;
print $temp, $_;
}
{
local $_ = 2;
$temp = "+" x $z; # $z is 1
$z = 1;
$_ = $_;
print $temp, $_;
}
{
local $_ = 3;
$temp = "+" x $z; # $z is 1
$z = 1;
$_ = $_;
print $temp, $_;
}
} continue {
print "\n";
}
所有这三个产生相同的输出:1+2+3
.
第二版
现在我们从原来的重新开始:
print$z,($z='+',$w)?'':$_ for 1..3;
并产生一个 deparsing 版本:
{
($w, $z) = (undef, undef);
for (1..3) {
print($z, ((($z = "+"), $w) ? "" : $_));
}
} continue {
print "\n";
}
后跟一个循环展开版本:
{
($w, $z) = (undef, undef);
{
local $_ = 1;
$z = "+";
print $z, $_;
}
{
local $_ = 2;
$z = "+";
print $z, $_;
}
{
local $_ = 3;
$z = "+";
print $z, $_;
}
} continue {
print "\n";
}
所有三个版本,出于我真的希望现在非常清晰的原因,打印相同的结果:+1+2+3
。
进一步启蒙
追踪正在发生的事情的最佳方法是对其进行跟踪:
tie $z, "Tie::Trace", "z";
tie $w, "Tie::Trace", "w";
($w, $z) = (undef, undef);
print'+'x$z,($z=1,$w)?'':$_ for 1..3;
print "\n";
{
($w, $z) = (undef, undef);
for (1..3) {
print(("+" x $z), ((($z = 1), $w) ? "" : $_))
}
} continue {
print "\n";
}
{
($w, $z) = (undef, undef);
{
local $_ = 1;
$temp = "+" x $z; # $z is undef
$z = 1;
print $temp, $_;
}
{
local $_ = 2;
$temp = "+" x $z; # $z is 1
$z = 1;
$_ = $_;
print $temp, $_;
}
{
local $_ = 3;
$temp = "+" x $z; # $z is 1
$z = 1;
$_ = $_;
print $temp, $_;
}
} continue {
print "\n";
}
($w, $z) = (undef, undef);
print$z,($z='+',$w)?'':$_ for 1..3;
print "\n";
{
($w, $z) = (undef, undef);
for (1..3) {
print($z, ((($z = "+"), $w) ? "" : $_));
}
} continue {
print "\n";
}
{
($w, $z) = (undef, undef);
{
local $_ = 1;
$z = "+";
print $z, $_;
}
{
local $_ = 2;
$z = "+";
print $z, $_;
}
{
local $_ = 3;
$z = "+";
print $z, $_;
}
} continue {
print "\n";
}
package Tie::Trace;
sub TIESCALAR {
my($class, $name, $value) = @_;
return bless {
NAME => $name,
VALUE => undef,
} => $class;
}
sub FETCH {
my($self) = @_;
my $name = '$' . $self->{NAME};
my $value = $self->{VALUE};
print STDERR "[reading value ", defined($value) ? $value : "undef",
" from $name]\n";
return $value;
}
sub STORE {
my($self, $value) = @_;
my $name = '$' . $self->{NAME};
print STDERR "[writing value ", defined($value) ? $value : "undef",
" into $name]\n";
$self->{VALUE} = $value;
return $value;
}
当你运行它时,它会产生这个相当令人满意的输出:
[writing value undef into $w]
[writing value undef into $z]
[reading value undef from $z]
[reading value undef from $z]
[writing value 1 into $z]
[reading value undef from $w]
[reading value 1 from $z]
[reading value 1 from $z]
[writing value 1 into $z]
[reading value undef from $w]
[reading value 1 from $z]
[reading value 1 from $z]
[writing value 1 into $z]
[reading value undef from $w]
1+2+3
[writing value undef into $w]
[writing value undef into $z]
[reading value undef from $z]
[reading value undef from $z]
[writing value 1 into $z]
[reading value undef from $w]
[reading value 1 from $z]
[reading value 1 from $z]
[writing value 1 into $z]
[reading value undef from $w]
[reading value 1 from $z]
[reading value 1 from $z]
[writing value 1 into $z]
[reading value undef from $w]
1+2+3
[writing value undef into $w]
[writing value undef into $z]
[reading value undef from $z]
[reading value undef from $z]
[writing value 1 into $z]
[reading value 1 from $z]
[reading value 1 from $z]
[writing value 1 into $z]
[reading value 1 from $z]
[reading value 1 from $z]
[writing value 1 into $z]
1+2+3
[writing value undef into $w]
[writing value undef into $z]
[writing value + into $z]
[reading value undef from $w]
[reading value + from $z]
[writing value + into $z]
[reading value undef from $w]
[reading value + from $z]
[writing value + into $z]
[reading value undef from $w]
[reading value + from $z]
+1+2+3
[writing value undef into $w]
[writing value undef into $z]
[writing value + into $z]
[reading value undef from $w]
[reading value + from $z]
[writing value + into $z]
[reading value undef from $w]
[reading value + from $z]
[writing value + into $z]
[reading value undef from $w]
[reading value + from $z]
+1+2+3
[writing value undef into $w]
[writing value undef into $z]
[writing value + into $z]
[reading value + from $z]
[writing value + into $z]
[reading value + from $z]
[writing value + into $z]
[reading value + from $z]
+1+2+3
概括
我现在已经费力地证明了这里实际发生的事情与传递引用无关。它仅与评估顺序有关,与其他无关。