有没有记录方式可以找到 Clojure 对象实现了哪些协议?反过来(显示给定协议扩展的类)很容易:(extenders protocol)。
有没有记录方式可以找到 Clojure 对象实现了哪些协议?反过来(显示给定协议扩展的类)很容易:(extenders protocol)。
(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)))
首先,它会查找当前命名空间中的所有符号(当然也可以扩展到所有命名空间),无论它们是协议定义还是网络(all-protocols)。接下来,它会查找给定的符号是否满足这些协议。
protocol?函数使用了:on-interface键,据我所知这个键并没有被记录在文档中,因此这个函数是不可移植的。
目前我无法尝试这个,但你可以尝试Java类方法:getGenericInterfaces
。这应该会给你一个接口列表。可能有其他类似的方法来获取这些信息,但我没有查看。
如果你也查看源代码,你会看到协议是如何设置的(你可以通过点击Clojure API中的链接来访问源代码)。在Clojure 1.3中,有一个“私有”函数长这样:
(defn- protocol?
[maybe-p]
(boolean (:on-interface maybe-p)))
这个函数被Clojure的extend
函数使用,以检查您是否实际提供了协议。如果您自己创建类似的函数,则可以过滤getGenericInterfaces
的结果。由于这是一个内部细节,可能会受到更改。
getInterfaces
可能更简单,作为 getGenericInterfaces
的合理替代方案。我在想如果对这个东西进行 AOT 编译会发生什么。 - hutch(extend ExistingClass MyProtocol ...)
扩展它。因此,自然而然地有一种方法来询问“哪些类扩展了这个协议”,但没有一种方法来询问相反的问题。 - Jouni K. Seppänen这是一个旧问题,而且已经有了一个被接受的答案……但是我可能会这样做:
(defprotocol FooP
(foo [this]))
(defrecord Foo []
FooP
(foo [this] :whatever))
> (satisfies? FooP (->Foo))
true
(defn interfaces [o]
(for [interface (.getInterfaces (class o))]
(.getCanonicalName ^Class interface)))
你可以检查
> (interfaces (->Foo))
("com.beoliver.FooP" "clojure.lang.IRecord" "clojure.lang.IHashEq" "clojure.lang.IObj" "clojure.lang.ILookup" "clojure.lang.IKeywordLookup" "clojure.lang.IPersistentMap" "java.util.Map" "java.io.Serializable")
> (interfaces [])
("clojure.lang.IObj" "clojure.lang.IEditableCollection" "clojure.lang.IReduce" "clojure.lang.IKVReduce")
> (interfaces {})
("clojure.lang.IObj" "clojure.lang.IEditableCollection" "clojure.lang.IMapIterable" "clojure.lang.IKVReduce")
bean
映射到接口而不是调用.getCanonicalName
,则可以看到所有选项。