原始答案
您需要通过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;
并生成一个解析版本:
{
($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
总结
我现在已经费力地证明了这里实际发生的事情与传递引用无关。它仅与评估顺序有关,与其他无关。