is Cool does Iterable does Sequence
Seq
表示可以生成值序列的任何内容。Seq
处于迭代它将消耗值的的状态中。对 Seq
调用 .cache
将使其存储生成的用于以后访问的值。
生成 Seq
的高级结构是 gather/take
,以及许多内置方法,如 map
和 grep
,低级构造函数可从迭代器或循环构造中创建 Seq
。
还可以使用 序列运算符 ...
或其变体之一构造 Seq
。
my = (1...5);say ; # OUTPUT: «(1 2 3 4 5)»say .^name; # OUTPUT: «Seq»
将 Seq
的值分配给数组会消耗一个非惰性的 Seq
。使用 lazy
语句前缀以避免在分配期间迭代 Seq
# The Seq created by gather ... take is consumed on the spot here.my = gather do ; # OUTPUT: «consuming...»# The Seq here is only consumed as we iterate over @a later.my = lazy gather do ; # outputs nothing..say for ; # OUTPUT: «consuming...one»
典型的用例是 IO::Handle
中的方法 lines
,如果它存储从文件中读取的所有行,则可能使用大量内存。所以
for open('README.md').lines ->
不会在内存中保留文件中的所有行。
这意味着您不能两次迭代同一个 Seq
对象(否则它无法丢弃旧值),因此这将导致死亡
my = 1, 2, 3;my = <a b c>;my \c = Z=> ;.say for c;.say for c; # failsCATCH ;# OUTPUT: «X::Seq::Consumed: This Seq has already been iterated, and its values consumed# (you might solve this by adding .cache on usages of the Seq, or# by assigning the Seq into an array)»
注意:即使程序没有缓存,任何程序也不应假设 Seq
只能迭代一次。缓存是一种不稳定的状态,作为优化向开发人员公开。Seq
可能被许多操作缓存,包括对 Seq
调用 .raku
(2019.11 版之前的 .perl
)(如果在非缓存迭代之前调用)。从 6.d 版开始,可以在已消耗的 Seq
上调用 .raku
(同样,2019.11 版之前的 .perl
)。如果程序假设 Seq
只能迭代一次,但后来在循环期间更改为调用其中一个操作,则该假设将失败。
在缓存的 Seq
上,当调用 &infix:<eqv>
、.Slip
、.join
、.List
、.list
、.eager
、.Array
和 .is-lazy
时,将使用缓存的列表。
即使是无限的,您也可以使用 Seq
智能匹配正则表达式
my = 1,1, *+* ... *;say [^1000] ~~ /^9999/; # OUTPUT: «Nil»
但是,在进行匹配时,无限或惰性的 Seq
将被激活,从而可能导致无限循环,因此请务必以某种方式限制搜索。
方法§
方法 new§
proto method new(Seq: |)multi method new(Seq: Iterator )multi method new(Seq:)
从作为单个参数传递的提供的迭代器创建一个新的 Seq
对象。如果在没有参数的情况下调用,则创建一个空的 Seq
。
方法 iterator§
method iterator(Seq:)
如果 Seq
未被缓存,则返回底层迭代器并将调用者标记为已消耗。如果对已消耗的序列调用,则抛出类型为 X::Seq::Consumed
的错误。
否则,返回缓存列表上的迭代器。
方法 is-lazy§
method is-lazy(Seq:)
仅当底层迭代器或缓存列表认为自己是惰性的时,返回 True
。如果在已消耗的序列上调用,则抛出类型为 X::Seq::Consumed
的错误。
方法 Seq§
multi method Seq(Seq:)
克隆对象。
方法 Capture§
method Capture()
将对象强制转换为 List
,然后将其强制转换为 Capture
。
方法 elems§
method elems(Seq:)
返回序列中的值数。如果无法预测此数字,则缓存 Seq
并对其进行评估,直到结束。
由于无限序列无法评估到结束,因此应该将此类序列声明为惰性的。对惰性 Seq
调用 .elems
会使用 X::Cannot::Lazy
fail。
方法 from-loop§
multi method from-loop(, :)multi method from-loop(, , :!, :)multi method from-loop(, , :)multi method from-loop(, , , :)
这些方法创建新的基于 Seq
的回调。
通常,它通过每次请求新元素时调用 &body
来生成无限 Seq
,并使用 &body
的返回值作为项目。这模拟(或实现)loop { body }
构造。
当多重包含 &cond
时,它会在每次调用 &body
之前调用,如果 &cond
返回假值,则终止序列。如果 $repeat
设置为真值,则省略对 &cond
的第一次调用,并立即调用 &body
。这模拟(或实现)while cond { body }
和 repeat { body } while cond
循环。
如果存在,则在每次调用 &body
后都会调用 &afterward
。
方法 sink§
method sink(--> Nil)
如果它是 Iterator
,则调用 sink-all
;如果 Sequence 是列表,则调用 sink
。
say (1 ... 1000).sink; # OUTPUT: «Nil»
您可能希望这样做,以产生这些值的副作用。
方法 skip§
multi method skip(Seq:)multi method skip(Seq: Whatever)multi method skip(Seq: Callable )multi method skip(Seq: Int() )multi method skip(Seq: , )
返回一个 Seq,其中包含调用者在丢弃下一个可用值中的 $n
个值后剩下的任何内容。$n
的负值计为 0。还可以使用 WhateverCode
来指示从末尾跳过多少个值。在请求的值数被丢弃之前,它将在惰性 Seq 上阻塞。
say (1..5).Seq.skip; # OUTPUT: «(2 3 4 5)»say (1..5).Seq.skip(3); # OUTPUT: «(4 5)»say (1..5).Seq.skip(5); # OUTPUT: «()»say (1..5).Seq.skip(-1); # OUTPUT: «(1 2 3 4 5)»
使用 Whatever
调用它将返回一个空 Seq
say <1 2 3>.Seq.skip(*); # OUTPUT: «()»
使用 Callable 的多重主要用于以这种方式使用
say (1..5).Seq.skip(*-3); # OUTPUT: «(3 4 5)»
它不会丢弃前 $n
个元素,而是丢弃所有内容除了 WhateverCode 指示的元素,在本例中丢弃所有内容,除了最后三个元素。
从语言版本 6.e
开始(早期实现存在于 Rakudo 编译器 2022.12+ 中),还可以指定多个参数值。然后将它们解释为要生成的值数,然后跳过,然后生成,依此类推。
say (1..12).Seq.skip(2,3,4); # OUTPUT: «(3 4 5 10 11 12)»
这首先跳过 2 个值,然后生成 3 个值(3、4、5),跳过 4 个值,然后生成其余值(10、11、12)。
如果指定的最终值处于“生成”位置,则将跳过 Seq
的其余部分。如果最终值处于“跳过”位置,则将生成 Seq
的其余部分。
say (1..10).Seq.skip(2,3,1,2); # OUTPUT: «(3 4 5 7 8)»say (1..10).Seq.skip(2,3,1); # OUTPUT: «(3 4 5 7 8 9 10)»
如果在“生成”位置指定了 Whatever
,则将生成 Seq
的其余部分。否则,将跳过 Seq
的其余部分。
say (1..10).Seq.skip(2,*); # OUTPUT: «(3 4 5 6 7 8 9 10)»say (1..10).Seq.skip(2,3,*); # OUTPUT: «(3 4 5)»
如果您想从生成值开始,而不是跳过值,请将 0 指定为第一个值。
say (1..10).Seq.skip(0,3,4); # OUTPUT: «(1 2 3 8 9 10)»
如果您想要一个无限重复的跳过和生成模式,则可以将参数指定为一个无限的 Seq
本身。
say (^20).Seq.skip(|(2,3) xx *); # OUTPUT: «(0 1 5 6 10 11 15 16)»
多方法 slice§
method slice(Seq: * --> Seq)
自 Rakudo 编译器的 2021.02 版本起可用。
slice
方法获取一系列单调递增的索引,用于从调用方中生成一个新 Seq
中的值。索引可以是单个数字或范围,只要它们的值递增即可。
这提供了一种比缓存 Seq
或将其转换为 List
或 Array
更有效的方法来获取 Seq
中的特定值。
say (1..10).Seq.slice(0, 3..6, 8); # OUTPUT: «(1 4 5 6 7 9)»