5

Clojureのセット、マップ、およびベクターがIPersistentCollectionとIFnの両方を実装している場合、ClojureはSayHiのどの実装を使用するかをどのように決定しますか?

(defprotocol SayHi
  (hi [this]))

(extend-protocol SayHi
  clojure.lang.IPersistentCollection
  (hi [_] (println "Hi from collection"))
  clojure.lang.IFn
  (hi [_] (println "Hi from Fn!"))
  clojure.lang.IPersistentSet
  (hi [_] (println "Hi from set!")))

(hi #{})
Hi from set!
(hi [])
Hi from collection
4

1 に答える 1

5

プロトコルのディスパッチは、関数の最初の引数の型で行われます。複数の実装が最初の引数の型と一致する場合、最も具体的な実装が選択されます。set( ) が両方を(hi #{})実装していても、呼び出しがコレクションまたは fn 実装ではなく、set 実装に解決されるのはそのためです。#{}

find-protocol-impl関数は、clojure-deftype.cljオブジェクト解決を実装するためのプロトコルを処理しているようです。

(defn find-protocol-impl [protocol x]
  (if (instance? (:on-interface protocol) x)
    x
    (let [c (class x)
          impl #(get (:impls protocol) %)]
      (or (impl c)
          (and c (or (first (remove nil? (map impl (butlast (super-chain c)))))
                     (when-let [t (reduce1 pref (filter impl (disj (supers c) Object)))]
                       (impl t))
                     (impl Object)))))))
于 2012-09-22T17:26:02.967 に答える