首页 > 解决方案 > 意外的哈希扁平化

问题描述

我正在寻找解释为什么这两个数据结构不相等:

$ perl6 -e 'use Test; is-deeply [ { a => "b" } ], [ { a => "b" }, ];'
not ok 1 -
# Failed test at -e line 1
# expected: $[{:a("b")},]
#      got: $[:a("b")]

Hashes 和 Arrays 中的尾随逗号是没有意义的,就像在 P5 中一样:

$ perl6 -e '[ 1 ].elems.say; [ 1, ].elems.say'
1
1

但是没有它,哈希会以某种方式丢失,并且会被展平为一对数组:

$ perl6 -e '[ { a => "b", c => "d" } ].elems.say;'
2

我怀疑一些伟大的列表重构法则在这里适用,但我想得到更详细的解释来理解这种扁平化背后的逻辑。

标签: hashmapraku

解决方案


就像在 P5 中一样,哈希和数组中的尾随逗号是没有意义的

不,这不是毫无意义的:

(1 ).WHAT.say ; # (Int)
(1,).WHAT.say ; # (List)

Great List Refactor 中最大的简化是切换到用于迭代功能的单参数规则1。也就是说,像 afor或数组和散列组合器(和下标)这样的特性总是得到一个参数。这确实是您原始示例的情况。

单个参数可能 - 通常是 - 一个值列表,甚至可能是一个列表列表等,但顶级列表仍然是迭代功能的单个参数。

如果迭代功能的单个参数扮演Iterable角色(例如列表、数组和散列),那么它就是迭代的。(这是一个不精确的公式;请参阅对“何时调用迭代器方法?”的回答以获得更精确的答案。)

所以这里要注意的关于额外逗号的关键是,如果单个参数没有起到Iterable作用,例如,那么1最终结果与参数是一个只包含那个值的列表完全相同(即1,) :

.perl.say for {:a("b")}   ; # :a("b")     Iterable Hash was iterated
.perl.say for {:a("b")} , ; # {:a("b")}   Iterable List was iterated
.perl.say for 1           ; # 1           Non Iterable 1 left as is
.perl.say for 1 ,         ; # 1           Iterable List was iterated

“在声明单个元素列表时保留结构 [除了] 使用尾随逗号”(参见下面的注释),即 停止像往常一样迭代单个Iterable值,是通过item使用 a 对其进行化$

my @t = [ $[ $[ "a" ] ] ];
@t.push: "b";
@t.perl.say; # [[["a"],], "b"]

1在 a 的情况下,迭代用于获取要传递给某些代码的值for;在作曲家的情况下,让值成为正在构造的数组/哈希的元素;在下标的情况下获取索引切片;等等其他迭代功能。


推荐阅读