5

给定 Clojure 中的集合、映射和向量同时实现 IPersistentCollection 和 IFn,Clojure 如何决定使用哪个 SayHi 实现:

(defprotocol SayHi
  (hi [this]))

(extend-protocol SayHi
  clojure.lang.IPersistentCollection
  (hi [_] (println "Hi from collection"))
  clojure.lang.IFn
  (hi [_] (println "Hi from Fn!"))
  clojure.lang.IPersistentSet
  (hi [_] (println "Hi from set!")))

(hi #{})
Hi from set!
(hi [])
Hi from collection
4

1 回答 1

5

协议调度是在函数的第一个参数的类型上完成的。当多个实现与第一个参数的类型匹配时,将选择最具体的实现。这就是为什么(hi #{})调用解析为 set 实现而不是 collection 或 fn 实现,即使 set ( #{}) 实现了这两者。

中的find-protocol-impl函数clojure-deftype.clj似乎处理实现对象解析的协议:

(defn find-protocol-impl [protocol x]
  (if (instance? (:on-interface protocol) x)
    x
    (let [c (class x)
          impl #(get (:impls protocol) %)]
      (or (impl c)
          (and c (or (first (remove nil? (map impl (butlast (super-chain c)))))
                     (when-let [t (reduce1 pref (filter impl (disj (supers c) Object)))]
                       (impl t))
                     (impl Object)))))))
于 2012-09-22T17:26:02.967 回答