1

我最近问为什么在 clojure 中不能完全实现接口和协议:

user=> (defprotocol P (foo [self]))
P
user=> (extend-type Long P)
nil
user=> (extends? P Long)
true
user=> (foo 1)
IllegalArgumentException No implementation of method: :foo of protocol: #'user/P found for class: java.lang.Long  clojure.core/-cache-protocol-fn (core_deftype.clj:527)

并被告知这是出于互操作的原因,实际上这不会成为问题。当然。

但显然extends?真的没有告诉我协议和类之间的关系:正如(extends? P C)并不意味着我可以调用fooC 类的对象,(not (extends? P C))也不意味着我不能调用fooC 类的对象:

user=> (defprotocol P (foo [self]))
P
user=> (extend-type Object P (foo [self] 1))
nil
user=> (extends? P Long)
false
user=> (foo 1)
1

现在我很困惑extends?应该给我什么信息...... satisfies?另一方面,正确处理第二种情况,但不是第一种。

4

1 回答 1

3

如有疑问,请检查代码:)。的实现extends?是这样的:

(defn extends? 
  "Returns true if atype extends protocol"
  {:added "1.2"}
  [protocol atype]
  (boolean (or (implements? protocol atype) 
               (get (:impls protocol) atype))))

所以它只是检查是否atype已经被协议扩展,并不意味着它已经实现了协议的所有方法。

:impls是一个映射,其中键是扩展协议的类型,值是映射,它具有该类型协议的方法实现。

user=> (defprotocol hello (a [self]))
hello
user=> (:impls hello)
nil
user=> (extend-type String hello)   
nil
user=> (:impls hello)            
{java.lang.String {}}
user=> (extend-type String hello (a [self] 10)) 
nil
user=> (:impls hello)                          
{java.lang.String {:a #<user$eval613$fn__614 user$eval613$fn__614@1d978ea>}}

另一方面,satisfies?您需要传递要检查协议的对象,而不是类型,extends?因此如果您查看satisfies?代码,则它要复杂extends一些,因为它必须检查的基类被协议扩展的对象。但是这两个函数都只是检查类型(或基类型)是否扩展了协议,并且它们不检查您是否实际实现了协议方法。

于 2012-05-30T04:07:12.993 回答