Sil*_*olo 8 raku raku-container
我正在Pair循环中构建多个对象,并且对每个对象的值使用相同的标量变量(尽管具有不同的值)。
作为我正在做的事情的简化示例,请考虑
\nmy @list;\nmy $acc = \'\';\n\nfor 1..30 -> $i {\n if $i % 5 == 4 {\n @list.push($i => $acc);\n $acc = \'\';\n } else {\n $acc = "$acc $i";\n }\n}\n\nsay @list;\nRun Code Online (Sandbox Code Playgroud)\n(当然,我的实际代码更复杂,并且从文件而不是预定义范围中读取,因此我不能像理论上那样完全消除循环)
\n我们累积包含写出的数字序列的字符串,创建一个将某些数字映射到低于该数字的值序列的对。
\n我希望这个程序的输出是
\n[4 => 1 2 3 9 => 5 6 7 8 14 => 10 11 12 13 19 => 15 16 17 18 24 => 20 21 22 23 29 => 25 26 27 28]\nRun Code Online (Sandbox Code Playgroud)\n但是,我目前得到
\n[4 => 30 9 => 30 14 => 30 19 => 30 24 => 30 29 => 30]\nRun Code Online (Sandbox Code Playgroud)\n据我了解,这是因为Pair当我将标量分配给其值字段时保留容器,因此我实际上创建了六对,它们的所有值都指向同一个(可变)容器。
文档表明了这一点,甚至还提出了一种解决方法
\n\n\n值得注意的是,当将标量分配为 Pair 的值时,该值保存该值本身的容器。这意味着可以从货币对本身外部更改该值:
\n...
\n可以改变上述行为,强制 Pair 删除标量容器并通过冻结方法保留有效值本身
\n
这有效。如果我替换@list.push($i => $acc)为
my $pair = ($i => $acc);\n$pair.freeze;\n@list.push($pair);\nRun Code Online (Sandbox Code Playgroud)\n然后代码会产生预期的输出。问题是,freeze已弃用,弃用警告下列出的唯一可能替代的代码是
\n\nRun Code Online (Sandbox Code Playgroud)\n$p.=Map.=head.say; # OUTPUT: \xc2\xaborange\xe2\x90\xa4\xc2\xbb \n
看起来它正在将 a 转换Pair为 a Map,然后再转换回来进行某种浅复制。不幸的是,这似乎不起作用,因为@list.push(($i => $acc).Map.head);会产生原始(不正确的)输出。
那么,既然Pair.freeze它显然已被弃用,那么现在在 Raku 中对对象的值大小进行去容器化的正确方法是什么?Pair
你们非常接近。
为了了解发生了什么,我将这一行放在print "$i: "; dd @list;for 循环结束之前。
这是一个示例:
19: Array @list = [4 => "", 9 => "", 14 => "", 19 => ""]
20: Array @list = [4 => " 20", 9 => " 20", 14 => " 20", 19 => " 20"]
21: Array @list = [4 => " 20 21", 9 => " 20 21", 14 => " 20 21", 19 => " 20 21"]
Run Code Online (Sandbox Code Playgroud)
因此,正如您所说,问题在于 $acc 容器只是被重用。在您的情况下,您需要将 Pair 值设置为 的内容$acc,而不是容器本身。
这些变体中的任何一个都可以代替您的推线:
@list.push($i => $acc<>);
@list.push($i => "$acc");
Run Code Online (Sandbox Code Playgroud)
decont<>运算符显式取消$acc 容器内容的容器化。
或者,也许更熟悉的是,""引号会生成一个新的 Str 值以及 $acc 当前值的副本。
| 归档时间: |
|
| 查看次数: |
146 次 |
| 最近记录: |