意外的哈希扁平化

时间:2018-05-20 21:59:36

标签: hashmap perl6

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

$ 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")]

哈希和数组中的尾随逗号与P5一样没有意义:

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

但是如果没有它,哈希就会以某种方式丢失并且变得扁平化为对阵:

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

我怀疑一些Great List Refactor法律适用于此,但我想获得更详细的解释,以了解这种扁平化背后的逻辑。

1 个答案:

答案 0 :(得分:6)

  

哈希和数组中的尾随逗号与P5一样没有意义

不,它没有意义:

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

Great List Refactor的大简化是为了迭代功能 1 切换到the single argument rule。也就是说,像for或数组和哈希作曲家(和下标)这样的功能总是得到一个参数。这确实是你原来的例子。

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

如果迭代特性的单个参数执行Iterable角色(例如列表,数组和散列),那么它将被迭代。 (这是一个不精确的表述;请参阅my answer至"何时调用迭代器方法?"更精确的方法。)

因此,关于额外逗号的关键是要注意,如果单个参数执行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

典型的方式"在声明单个元素列表时使用尾随逗号来保留结构[除了]以外#34; (见下面的评论),即 停止正常迭代的单个Iterable值,通过 item - 使用$进行迭代:

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

1 迭代用于获取在for的情况下传递给某些代码的值;获取值以成为在作曲家的情况下构造的数组/散列的元素;在下标的情况下获得索引切片;等等其他迭代特征。