2024年Clojure状态调查!中分享你的想法。

欢迎!请参阅关于页面,获取更多有关此如何工作的信息。

0
data.int-map
编辑

这是一个问题,在 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 提出相同的问题


编辑了
我认为这个问题的难点可能在于类型转换行为。例如,你可以在 int-map 中插入一个 int、BigInt 或 short,它会被转换为一个 long。但这与 HashMap 的行为不同,HashMap 会直接存储传入的键。这本身可能就足以让整个想法泡汤。尽管如此,这仍然值得思考。

1 个答案

+1

被选中
 
最佳答案

int-map/set 声明的约束是它们具有整数键,并且在这种用例中可以获得性能优势。如果你需要这一功能,你应该使用 int-map。如果不需要,你应该使用标准映射。

因此,我认为向 int-map 添加非 int 键会抛出异常,这一点不应该改变。

...