给定Clojure中的set,map和vector实现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
Run Code Online (Sandbox Code Playgroud)
协议分派是在函数的第一个参数的类型上完成的.当多个实现与第一个参数的类型匹配时,将选择最具体的实现.这就是为什么(hi #{})调用解析为set实现而不是集合或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)))))))
Run Code Online (Sandbox Code Playgroud)