🎄 9/25. 关于 X 的更多东西, Perl 6 中的 .. 和 …

欢迎来到 Perl 6 One-Liner Advent Calendar 的第9天! 在第6天,我们有一个带有交叉算子的构造,(999...100) X* (999...100)。 今天,我们将从11月开始进入类似的结构:

1
1..10 X* 1..10

它打印乘积表的项,数字从1到10:

1
(1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100)

关于这样的结构,有几点需要了解。

您可能已经注意到 999 ... 1001..10 之间存在两个细微差别。 在一种情况下,有三个点,另一个只有两个点。 在第一种情况下,边界在递减数字,在第二种情况下,是递增数字。

Perl 6 中的两个点是范围运算符。 它创建一个 Range,或者换句话说,创建 Range 类型的对象。

Perl 6 中的三个点是序列运算符。 在我们的示例中,它创建序列或 Seq 类型的对象。

您始终可以通过在对象上调用 WHAT 方法来检查类型(REPL会话的片段如下所示):

1
2
3
4
> (1..10).WHAT
(Range)
> (1...10).WHAT
(Seq)

查看 Rakudo 的源代码也很有趣,看看 RangeSeq 有哪些属性。

1
2
3
4
5
6
7
8
9
my class Range is Cool does Iterable does Positional {
has $.min;
has $.max;
has int $!excludes-min;
has int $!excludes-max;
has int $!infinite;
has int $!is-int;
. . .
}
1
2
3
4
my class Seq is Cool does Iterable does Sequence {
has Iterator $!iter;
. . .
}

Range 对象中,有最小值和最大值,而在 Seq 中我们看到一个迭代器。

在某些情况下,例如,在一个简单的循环中,您可以在范围或序列之间进行选择:

1
2
.say for 1..10;
.say for 1...10;

但如果你想倒数,范围将不起作用:

1
2
> .say for 10..1;
Nil

使用序列就没问题:

1
2
> .print for 10...1;
10987654321>

在开始感觉良好之前,使用范围和序列是明智的。 将它们保存在变量中,在操作中使用,使用 saydd 打印。

作为一个起点,考虑以下三个操作:

1
2
3
(1, 2, 3) X* (4, 5, 6);
(1..3) X* (4..6);
(1...3) X* (4...6);

这就是你明天的 Advent 之前你可以做的事情!