目前,Clojure 的解构实现会从遇到的满足 clojure.core/seq? 的任何值创建一个哈希表。我认为这会产生不希望的不利影响,使得无法在也是 Seq 的自定义关联类型上应用解构。这出现在尝试解构标记值类的实例时,该类在模式匹配时行为类似于 [k v] 序列,但由于 v 已知是映射,因此在映射部分上也是关联的,以避免更新保留标记的语法开销。
;; 此类类型的一个草图
(deftype ATaggedVal [t v]
clojure.lang.Indexed
(nth [self i] (nth self i nil))
(nth [self i o] (case i (0) t (1) v o))
clojure.lang.Sequential
clojure.lang.ISeq
(next [this] (seq this))
(first [this] t)
(more [this] (.more (seq this)))
(count [this] 2)
(equiv [this obj] (= (seq this) obj))
(seq [self] (cons t (cons v nil)))
clojure.lang.Associative
(entryAt [self key] (.entryAt v key))
(assoc [_ sk sv] (ATaggedVal. t (.assoc v sk sv)))
clojure.lang.ILookup
(valAt [self k] (.valAt v k))
(valAt [self k o] (.valAt v k o))
clojure.lang.IPersistentMap
(assocEx [_ sk sv] (ATaggedVal. t (.assocEx v sk sv)))
(without [_ sk] (ATaggedVal. t (.without v sk))))
所以使用这样的东西:
(let [{:keys [x]} (ATaggedVal. :foo {:x 3 :y 4})] x)
;; 想要 3
=> nil
由于对于任何满足 clojure.core/get 将会行为的数据类型 T,T 应该满足 clojure.core/map?,解构的行为应该只是当 map? 不满足时才简单地改变以构建哈希表。
附加的补丁实现了这个改变。