为什么斐波那契的这个 Perl 单行有效?
Why is this Perl one-liner of Fibonacci working?
print$f+=$z=$f-$z,$/for--$z..8
或者,如果将 $z 替换为 $!,则可以执行以下操作。
print$f+=$!=$f-$!for--$!..8
但是为什么呢? $!
是错误的 perlval,不是吗?
这是一种混淆。它之所以有效,是因为(来自 perlvar
):
$ERRNO $!
When referenced, $! retrieves the current value of the C errno integer variable. If $! is assigned a numerical value, that value is
stored in errno. When referenced as a string, $! yields the system
error string corresponding to errno.
例如,
$ perl -M5.010 -e'
$! = 2;
say 0+$!; # Treat as number
say "$!"; # Treat as string
$! = 3;
say 0+$!;
say "$!";
'
2
No such file or directory
3
No such process
如果我们放入一些 space 以使其更具可读性:
print $f += $z = $f - $z ,$/ for --$z .. 8
让我们将不同的部分提取到正常代码中。首先,使用常规 for
循环。
for (--$z .. 8) {
print $f += $z = $f - $z ,$/
}
前缀--
auto-decrement operator将取未初始化的变量$z
,将其强制转换为0,减去1,然后return-1
。这与将 -1
分配给 $z
.
基本相同
我们从 -1 循环到 8。这些数字是无关紧要的,因为它们被分配给 $_
,它从未被使用过。基本上我们只是循环 10 个步骤。此步骤中使用的变量无关紧要。它可以是任何可以赋值的变量,这就是为什么 $!
-- OS error variable 也能工作。
我们可以将语句简化为
$z = -1;
for (0 .. 9)
打印语句主要打印两件事:
$f += $z = $f - $z
和
$/
两个用逗号分隔的语句,
,表示它是一个列表。预定义变量$/
是input record separator;默认情况下它是换行符(OS 依赖)。 print
接受一个参数列表,这就是它的工作方式。 print
自动换行与 say
相同。所以我们可以交换它并将代码简化为:
say $f += $z = $f - $z
让我们解开那个作业。它基本上是两个语句,从右到左按顺序完成,以打印结尾:
$z = $f - $z
$f += $z
say $f
如果我们把它放在一起,我们得到:
$z = -1;
for (0 .. 9) { # loop 10 times
$z = $f - $z; # calculate increment
$f += $z; # increment value
say $f; # print value
}
它是这样工作的:
我们知道 $z
最初是 -1
来自 for 循环。由于 $f
从未使用过,因此它将是未定义的(在减法上下文中使用时将被转换为 0)。所以我们得到:
$z = $f - $z = undef - (-1) = 0 + 1 = 1
$f += $z = 1 => $f = $f + 1 => $f = 1
因此第一个循环迭代打印 1。下一个回合
$z = $f - $z = 1 - 1 = 0
$f += $z = 0 => $f = $f + 0 = 1 + 0 = 1
下一张也是1。下一回合
$z = $f - $z = 1 - 0 = 1
$f += $z = 1 => $f = $f + 1 = 1 + 1 = 2
以此类推
print$f+=$z=$f-$z,$/for--$z..8
或者,如果将 $z 替换为 $!,则可以执行以下操作。
print$f+=$!=$f-$!for--$!..8
但是为什么呢? $!
是错误的 perlval,不是吗?
这是一种混淆。它之所以有效,是因为(来自 perlvar
):
$ERRNO $!
When referenced, $! retrieves the current value of the C errno integer variable. If $! is assigned a numerical value, that value is stored in errno. When referenced as a string, $! yields the system error string corresponding to errno.
例如,
$ perl -M5.010 -e'
$! = 2;
say 0+$!; # Treat as number
say "$!"; # Treat as string
$! = 3;
say 0+$!;
say "$!";
'
2
No such file or directory
3
No such process
如果我们放入一些 space 以使其更具可读性:
print $f += $z = $f - $z ,$/ for --$z .. 8
让我们将不同的部分提取到正常代码中。首先,使用常规 for
循环。
for (--$z .. 8) {
print $f += $z = $f - $z ,$/
}
前缀--
auto-decrement operator将取未初始化的变量$z
,将其强制转换为0,减去1,然后return-1
。这与将 -1
分配给 $z
.
我们从 -1 循环到 8。这些数字是无关紧要的,因为它们被分配给 $_
,它从未被使用过。基本上我们只是循环 10 个步骤。此步骤中使用的变量无关紧要。它可以是任何可以赋值的变量,这就是为什么 $!
-- OS error variable 也能工作。
我们可以将语句简化为
$z = -1;
for (0 .. 9)
打印语句主要打印两件事:
$f += $z = $f - $z
和
$/
两个用逗号分隔的语句,
,表示它是一个列表。预定义变量$/
是input record separator;默认情况下它是换行符(OS 依赖)。 print
接受一个参数列表,这就是它的工作方式。 print
自动换行与 say
相同。所以我们可以交换它并将代码简化为:
say $f += $z = $f - $z
让我们解开那个作业。它基本上是两个语句,从右到左按顺序完成,以打印结尾:
$z = $f - $z
$f += $z
say $f
如果我们把它放在一起,我们得到:
$z = -1;
for (0 .. 9) { # loop 10 times
$z = $f - $z; # calculate increment
$f += $z; # increment value
say $f; # print value
}
它是这样工作的:
我们知道 $z
最初是 -1
来自 for 循环。由于 $f
从未使用过,因此它将是未定义的(在减法上下文中使用时将被转换为 0)。所以我们得到:
$z = $f - $z = undef - (-1) = 0 + 1 = 1
$f += $z = 1 => $f = $f + 1 => $f = 1
因此第一个循环迭代打印 1。下一个回合
$z = $f - $z = 1 - 1 = 0
$f += $z = 0 => $f = $f + 0 = 1 + 0 = 1
下一张也是1。下一回合
$z = $f - $z = 1 - 0 = 1
$f += $z = 1 => $f = $f + 1 = 1 + 1 = 2
以此类推