这是一个问题,在 Clojure 中,我们有一些典型的 HashMap,它们允许在它们上面关联任何类型的键,然后又有一些更专门类型的映射用于特定的键。然而,大多数映射也允许将键关联到它们通常的范围之外,当操作会破坏数据结构的不变式时,它们会优雅地回退到 HashMap。以下是一些示例
记录是开放的,当删除记录字段时会回退到 HashMap
(defrecord Person [name lang])
;; => clojure.data.int_map_test.Person
(let [p (->Person "john" "en_CA")]
[p (assoc p :foo :bar) (dissoc p :lang)])
;; =>
;; [#clojure.data.int_map_test.Person{:name "john", :lang "en_CA"}
;; #clojure.data.int_map_test.Person{:name "john", :lang "en_CA", :foo :bar}
;; {:name "john"}]
另一方面,struct-maps 对关联是开放的,但对删除是关闭的
(let [sm (struct-map (create-struct :name :lang) :name "John" :lang "en_CA")]
[(assoc sm :foo "bar")
(try (dissoc sm :lang) (catch Exception e (.toString e)))])
=> [{:name "John", :lang "en_CA", :foo "bar"}
"java.lang.RuntimeException: Can't remove struct key"]
另一个例子是 ArrayMaps,随着它们的增长最终会变成 HashMap。这并不完全一样,没有特定的键在映射之外,但在更广义的情况下,当操作违反了不变式或性能预期时,就回退到一般的 HashMap。
这让我想知道,人们对于 int-map/int-set 的看法如何,当你尝试添加非整数字符时,它会产生异常。
(assoc (i/int-map 1 2) :a "b")
ClassCastException class clojure.lang.Keyword cannot be cast to class java.lang.Number
是否应该修改为回退到 HashMap?这似乎更符合 Clojure 开放数据结构的哲学。
它可以通过类似于 PersistentStructMap
的方式实现,它在一个额外的映射中存储不属于结构定义的额外的键/值对。
final IPersistentMap ext;
同样,也可以在 PersistentIntMap 中这样做。
(deftype PersistentIntMap
[^INode root
^long epoch
meta
^IPersistentMap ext]
;; ...
你有什么看法?
还有,对于 int-sets 提出相同的问题