2011-01-10 78 views

回答

5

我結束了以下實現:

(defn protocol? [maybe-p] 
    (boolean (:on-interface maybe-p))) 

(defn all-protocols [] 
    (filter #(protocol? @(val %)) (ns-publics *ns*))) 

(defn implemented-protocols [sym] 
    (filter #(satisfies? @(val %) sym) (all-protocols))) 

首先,它會在當前命名空間中所有的符號(當然你也可以此擴大到所有命名空間)無論是協議定義或淨(所有-protocols)。接下來,它會查找給定的符號,如果它滿足這些協議之一。

該協議?函數使用:on-interface key,這是沒有記錄的afaik,所以這個函數是不可移植的。

+0

'protocol?'在排序映射上失敗,至少在Clojure 1.8中失敗。看[這個問題](http://stackoverflow.com/q/37410580/1393162)。 –

0

我目前實際上無法嘗試此操作,但您可能需要嘗試Java類方法:getGenericInterfaces。這應該給你一個接口列表。可能有其他方法可以使用類似的方法獲取這些信息,但我沒有看過。

如果你也看看源代碼,你會看到如何設置協議(你可以通過點擊clojure api中的鏈接來獲得源代碼)。用Clojure 1.3還有一個「私人」功能,看起來像這樣:

(defn- protocol? 
    [maybe-p] 
    (boolean (:on-interface maybe-p))) 

此功能使用Clojure的extend函數來檢查,你實際上已經提供了一個協議。如果你創建自己的功能,你可以過濾getGenericInterfaces的結果。由於這是內部細節,因此可能會有所變更。

+0

getGenericInterfaces給我(clojure.lang.IObj clojure.lang.ILookup clojure.lang.IKeywordLookup clojure.lang.IPersistentMap java.util.Map java.io.Serializable)但不是實現的協議。我想我必須深入研究源代碼,看看它是如何完成的。 –

+0

剛回到我的機器,我沒有比你更進一步。使用'getInterfaces'作爲'getGenericInterfaces'的合理替代方法可能更簡單。我想知道如果你AOT編譯的話會發生什麼。 – hutch

+2

協議點的一部分是一個類不需要實現一個接口來擴展一個協議:你可以定義你自己的協議,然後說一些預先存在的類用'(擴展ExistingClass MyProtocol ...)'擴展它。因此,有一種方法可以問「什麼類擴展了這個協議」,而不是一種提出相反問題的方法。 –