1

例えば、

(defprotocol P
  (foo [x])
  (bar [x]))


(extend-protocol P

  Superclass ;; a java abstract class
  (foo [x]
    (println "superclass"))

  Subclass ;; a concrete java class implementing the above abstract class
  (foo [x]
    (foo (cast Superclass x))))

呼び出す場合

(foo subclass-instance)

明らかにスタックオーバーフローが発生しますが、ここでやろうとしていることを達成する方法はありますか?つまり、同じ関数を呼び出しますが、一般的なスーパークラス/インターフェイスとして偽装しますか?

更新:私が求めているユースケースを示すより明確な例:

(defprotocol P
  (extract-properties-into-map [self]))

(extend-protocol P
  PropertyContainer  ;; abstract class
  (extract-properties-into-map
    [this]
    (into {} (for [[k v] (.getProperties this)] [(keyword k) (read-string v)])))

  Foo
  (extract-properties-into-map
    [this]
    (assoc {:properties (extract-properties-into-map
                          ^PropertyContainer this)} ;; this is where it falls apart
      :foo-type (.getFooType this)
      :foo-permissions (.getPermissions this)
      :foo-whatever (.getWhatever this))))
4

2 に答える 2

0

の問題は、オブジェクトが is-a 関係を満たさない場合に例外をスローするだけで、 のcastように機能することです。type assertion

(defn cast
  "Throws a ClassCastException if x is not a c, else returns x."
  {:added "1.0"
   :static true}
  [^Class c x] 
  (. c (cast x)))

別の関数でディスパッチするために返される新しいインターフェイスはありません。つまり、スタック オーバーフローがあります。

のプロトコルを拡張することの意味がわかりませんInterfacetype実装を提供しているので、最初に定義し、そのスーパータイプのプロトコルを拡張する必要があると思います。

于 2013-10-23T15:58:33.240 に答える
0

編集: https://gist.github.com/michalmarczyk/1715851に基づくわずかに優れたdelegating-proxy回答

(defprotocol P
   (foo [x])
   (bar [x]))


(extend-protocol P

  Number ;; a java abstract class
  (foo [x]
      (println "superclass:" x))

  Integer ;; a concrete java class implementing the above abstract class
   (foo [x]
    (foo (delegating-proxy x [Number] []))))

と呼ばれる

(foo (Integer. 1))
=> superclass: 1

質問のとおりに実行し、元のをラップしxます。要件によってはfoo、プロトコルに含まれていない関数に委譲した方がよい場合もあります。superfoo

(defn superfoo [x] { :byte (.byteValue x) })

(defprotocol P
  (foo [x])
  (bar [x]))


(extend-protocol P

  Number ;; a java abstract class
   (foo [x]
     (superfoo x))

  Integer ;; a concrete java class implementing the above abstract class
    (foo [x]
      (merge (superfoo x) { :f (.floatValue x)})))

根本的な問題は、プロトコルがクラスの継承について知らないことだと思います。また、Clojure はオブジェクトを型に強制するのを待つ必要があるようです。この場合、型ヒントは機能しません。

于 2013-10-23T18:28:33.773 に答える