在Clojure中,为什么`into`地图(`(into{},,,)`)适用于`vectors`而不适用于`lists`?
我可以用向量列表构建地图:
user=> (into {} (list (vector "a" "b") (vector "c" "d")))
{"a" "b", "c" "d"}
但是,如果我尝试使用列表列表来执行此操作,则会失败:
user=> (into {} (list (list "a" "b") (list "c" "d")))
Execution error (ClassCastException) at user/eval3 (REPL:1).
class java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')
为什么?
回答
当你这样做时,(into {} coll)它相当于(reduce conj {} coll)所以你的每个元素都coll被用作第二个参数,conj以散列映射作为第一个参数。
conj内置clojure.lang.RT并调用(在这种情况下)APersistentMap.cons()添加这里的元素:https : //github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L24
从中可以看出,如果参数是 a MapEntry,它将作为键/值对添加到哈希映射中:(seq my-hash-map)生成一个MapEntry项目序列。
如果参数是一个具有两个元素的向量,它将作为键/值对添加,其中键是该向量的第一个元素,值是该向量的第二个元素。
否则,它会尝试将参数转换为序列,然后将每个元素强制转换MapEntry为键/值对并将其添加为键/值对。
当您传递向量列表(双元素向量)时,它们会根据上述第二种情况作为键/值对添加。当您传递列表列表时,会调用第三种情况,它会尝试将内部列表的每个元素强制转换为 a MapEntry-- 失败,因为这些元素是String's。
THE END
二维码