2012-09-22 25 views
5

鉴于Clojure的一组,地图和矢量同时实现IPersistentCollection和IFN,如何Clojure的决定哪种实现的sayHi的使用方法:分辨率的Clojure协议呼叫时类实现多个接口

(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 

回答

5

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

clojure-deftype.cljfind-protocol-impl功能似乎处理协议,以实现对象的分辨率:

(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))))))) 
+1

你能指出Clojure的源代码中做到这一点?我一直无法找到它 – DanLebrero

+1

@dAni更新了答案 –