Wait the light to fall

开关

焉知非鱼

toggle 字面意思是开关, 函数签名如下:

method toggle(Any:D: *@conditions where .all ~~ Callable:D, Bool :$off  --> Seq:D)

它接收一个数组, 数组中的每个元素都是一个 Callable

它迭代调用者, 产生一个 Seq, 根据开关是开还是关把接收到的值填充到结果中, 开关是开还是关取决于 @conditions 数组里面调用 Callables 的结果:

say (1..15).toggle(* < 5, * > 10, * < 15); # OUTPUT: «(1 2 3 4 11 12 13 14)␤» 
say (1..15).toggle(:off, * > 2, * < 5, * > 10, * < 15); # OUTPUT: «(3 4 11 12 13 14)␤» 

想象一下开关是打开还是关闭(TrueFalse),如果它打开则产生值。默认情况下,该开关的初始状态处于 “on” 位置,除非 :$off 设置为 true 值,在这种情况下,初始状态将为"off"。

@conditions 的头部开始拿出一个 Callable(如果有的话)并且它成为当前的 tester。通过使用该值调用 tester Callable 来测试原始序列中的每个值。我们想象的开关的状态被设置为 tester 的返回值:如果它是真的,将开关设置为 “on”,否则将其设置为 “off”。

无论何时切换开关(即从"off"切换到"on"或从"on"切换到"off"),当前 tester Callable 将替换为 @conditions 中的下一个 Callable,如果可用,将用于测试进一步的值。如果没有更多可用的 tester Callables,则开关将保持其当前状态,直到迭代结束。

# our original sequence of elements: 
say list ^10; # OUTPUT: «(0 1 2 3 4 5 6 7 8 9)␤» 
# toggled result: 
say ^10 .toggle: * < 4, * %% 2, &is-prime; # OUTPUT: «(0 1 2 3 6 7)␤» 
 
# 第一个 tester Callable 是 `* < 4` 开关的初始状态是 "on". 
# 当我们迭代我们的原始序列时: 
# 0 => 0 < 4 === True  开关是开着的, 值进入到结果中, 开关切换
#                      所以我们继续使用同一个 Callable: 
# 1 => 1 < 4 === True  same 
# 2 => 2 < 4 === True  same 
# 3 => 3 < 4 === True  same 
# 4 => 4 < 4 === False 开关关闭, "4" 没有进入到结果中 
#                      此外, 我们的开关发生切换,  
#                      所以, 我们切换到下一个 Callable 
# 5 => 5 %% 2 === False  开关仍旧关闭, 继续尝试找到满足条件的值 
# 6 => 6 %% 2 === True   开关开启, 把 "6" 放入到结果中 
#                        开关切换, 所以我们会使用下一个 tester Callable 
# 7 => is-prime(7) === True  开关仍然开启, 将值放入结果中并继续 
# 8 => is-prime(8) === False 开关现在关闭, "8" 没有被放入到结果中
#                            开关切换, 但是我们再没有  
#                            tester Callables 了, 
#                            所以对于剩下的序列它会一直保持关闭. 

由于开关状态的切换加载下一个 tester Callable,设置 :$offTrue 值会影响第一个 tester 何时被丢弃:

# our original sequence of elements: 
say <0 1 2>; # OUTPUT: «(0 1 2)␤» 
# toggled result: 
say <0 1 2>.toggle: * > 1; # OUTPUT: «()␤» 
 
# 第一个 tester Callable 是 `* > 1` 并且开关的初始状态是 "on". 
# 当我们迭代我们的原始序列时: 
# 0 => 0 > 1 === False  开关关闭, "0" 没有进入到结果中. 
#                      此外, 发生了切换, 所以我们要改变 tester Callable 
#                      但是因为我们没有 tester Callable 可用了 
#                      所以开关会保持 "off" 状态直到结束
# our original sequence of elements: 
say <0 1 2>; # OUTPUT: «(0 1 2)␤» 
# toggled result: 
say <0 1 2>.toggle: :off, * > 1; # OUTPUT: «(2)␤» 
 
# 第一个 tester Callable 是 `* > 1` 并且开关的初始状态是 "off". 
# 当我们迭代我们的原始序列时: 
# 0 => 0 > 1 === False  开关关闭, "0" 没有进入到结果中 
#                       这一次开关没有发生切换 
#                       所以我们继续使用我们当前的 tester Callable 
# 1 => 1 > 1 === False  same 
# 2 => 2 > 1 === True   开关开启, "2" 进入到结果中

一个例子:

my $excerpt = q:to/END/;
Here's some unimportant text.
=begin code
This code block is what we're after.
We'll use 'ff' to get it.
=end code
More unimportant text.
=begin code
I want this line.
and this line as well.
HaHa
=end code
More unimport text.
=begin code
Let's to go home.
=end code
END


.say for $excerpt.lines
  .toggle( * ~~ /'=begin code'/,
           * ~~ /'=end code'/)

输出:

=end codeMore unimportant text.
=begin code
I want this line.
and this line as well.
HaHa
=end code
More unimport text.
=begin code
Let's to go home.
=end code