deepmap 创建的数组中的不可变(非容器化)元素

Immutable (uncontainerized) elements in arrays created by deepmap

如果我正确理解 Raku 文档,数组的元素总是容器化的,即标量。但是,deepmap 方法似乎创建了(内部)具有未容器化元素的数组:

my @a = [1, [2, 3]];
my @b = @a.deepmap: *.clone;
say @b[0].VAR.^name;     # Scalar, this is OK
say @b[1].^name;         # Array, as expected
say @b[1][0].VAR.^name;  # Int, why?
@b[0] = 4;               # this works
@b[1][0] = 5;            # error: Cannot assign to an immutable value

为什么会这样?

对于上下文,我最初想使用 .deepmap: *.clone 创建一个深拷贝,但我需要该拷贝是可变的。我使用 @a.deepmap: { my $ = .clone } 解决了这个问题,但我仍然很好奇为什么会这样。

If I understand the Raku docs correctly, the elements of Arrays are always containerized, i.e. Scalars.

几乎正确,但不完全正确 – 数组初始化(即使用 [1, 2])将值容器化,但这并不意味着元素总是容器化.例如,您可以 explicitly bind a value 到数组中的某个位置。

或者,正如您所发现的,当以不寻常的方式创建数组时,您可能会得到一个非容器化的值。让我们看看 deepmap 在这里做了什么:

my @a = [1, [2, 3]];

@a.deepmap({.say; $_});  # OUTPUT: «1␤2␤3␤»
say @a.raku;             # OUTPUT: «[1 [2 3]]»

这是怎么回事?好吧,deepmap 递归地下降到结构中并在每个叶元素上调用函数(这就是为什么它在第二次迭代中打印 2 而不是 [2 3] 的原因)。然后它绑定结果到它正在迭代的插槽。

因此,对于 .clonedeepmap 向下到达叶节点(例如,2)并对该值调用 .clone,得到 2Int)并将其绑定到数组中的位置。

您想要的似乎是 .clone[2 3] 上被调用,而不是 2。如果是这样,您可以对具有一层嵌套(如上)和 .map(*.clone) 的列表执行此操作;对于更复杂的嵌套,您可以在 map 表达式中使用 duckmap 或测试(或者,正如您发现的那样,在叶值上调用 .clone 并手动添加 Scalar 。 )