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?に、プロトコルとクラスの関係については何も教えてくれません:クラス C のオブジェクトを(extends? P C)呼び出すことができることを意味しないのと同様に、クラス C のオブジェクトを呼び出すことができないことを意味するものでもありません。foo(not (extends? P C))foo

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?一方、2番目のケースは正しく処理しますが、最初のケースは処理しません。

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 に答える