Raku中Slip的外层列表判定规则及未展平异常行为咨询
核心结论
这个行为完全可以通过Raku中Slip、数组下标操作的原生语义解释,不需要把列表赋值当作特殊场景处理,核心是两个容易混淆的认知误区:
- Slip的自动展平不是永久属性,仅发生在Slip被创建后直接进入列表构造上下文的瞬间
- 单个数组下标(
@a[N])的赋值/绑定操作语义上永远只会操作1个元素位置,不可能插入多个元素,和右侧值的类型无关
具体原理拆解
- 第一个符合预期的示例逻辑:
dd my @a = 1, |(2, 3); # OUTPUT: «Array @a = [1, 2, 3]»
这里|(2, 3)生成Slip后直接处于列表字面量的顶层上下文,触发自动展平,最终赋值给@a的列表是(1,2,3),结果自然符合预期。
- 第二个示例的问题所在:
dd my @b = do {@a[2] := |(3, 4); @a} # OUTPUT: «Array @b = [1, 2, slip(3, 4)]»
@a[2] := |(3, 4)是单个元素绑定操作:你是把@a的第3个元素位置直接绑定到Slip对象本身。单下标操作的语义限制了它只会修改1个元素位,哪怕右侧是Slip也不会触发展平,此时@a的结构就是[1, 2, slip(3,4)]。
后续把@a赋值给@b时,是迭代@a的已有元素逐个赋值,Slip此时已经是@a的一个独立元素,不会再触发自动展平,因此最终@b中会保留slip(3,4)这个元素。
- 和
splice的差异原因:@a.splice(2, 1, [3,4])本身就是专门用于批量增删数组元素的API,它的第三个参数天然处于列表迭代上下文,传入的列表会被展开为多个元素插入,这和单下标操作的语义完全不同,不存在一致性问题。
实现你预期效果的写法
如果要通过赋值实现类似splice的替换多个元素的效果,应该使用数组分片语法,触发列表上下文展平Slip:
dd my @b = do {@a[2..2] = |(3, 4); @a} # OUTPUT: «Array @b = [1, 2, 3, 4]»
内容的提问来源于stack exchange,提问作者codesections
相关产品推荐
相关产品推荐

