如果我正确理解 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
Run Code Online (Sandbox Code Playgroud)
为什么会出现这种情况?
对于上下文,我最初想用来.deepmap: *.clone创建深层副本,但我需要副本是可变的。我通过使用解决了这个问题@a.deepmap: { my $ = .clone },但我仍然很好奇为什么会发生这种情况。
cod*_*ons 10
\n\n如果我正确理解 Raku 文档,数组的元素总是容器化的,即标量。
\n
这几乎是正确的,但不完全是 \xe2\x80\x93 数组初始化(即使用[1, 2])将值容器化,但这并不意味着元素总是容器化的。例如,您可以显式绑定一个值到数组中的位置。
或者,正如您所发现的,当以不寻常的方式创建数组时,您可能会得到一个非容器化的值。让我们看看是什么deepmap这里做了什么:
my @a = [1, [2, 3]];\n\n@a.deepmap({.say; $_}); # OUTPUT: \xc2\xab1\xe2\x90\xa42\xe2\x90\xa43\xe2\x90\xa4\xc2\xbb\nsay @a.raku; # OUTPUT: \xc2\xab[1 [2 3]]\xc2\xbb\nRun Code Online (Sandbox Code Playgroud)\n这是怎么回事?好吧,deepmap是递归地下降到结构中并在每个叶元素上调用函数(这就是它打印2而不是[2 3]在第二次迭代时打印的原因)。然后就绑定了到它正在迭代的槽。
因此,随着.clone,deepmap向下到达叶子(例如2)并调用.clone该值,得到2(一个Int ) 并将其绑定到数组中的位置。
看来你想要发生的事情是为了.clone被召唤[2 3],而不是2。如果是这样,您可以对具有一级嵌套的列表(如上)执行此操作.map(*.clone);对于更复杂的嵌套,您可以在表达式duckmap内使用或测试map(或者,正如您所发现的,调用.clone叶值并添加Scalar。)