如果在deftype形式中错误地多次指定协议,可能会省略该协议的一些方法实现。
重新生产
(defprotocol P (f [this]) (g [this]))
(deftype T []
P
(f [this] :F)
P
(g [this] :G))
(def t (->T))
(f t)
;; Execution error (AbstractMethodError) at user/eval187 (REPL:1).
;; Receiver class user.T does not define or inherit an implementation of the resolved method 'abstract java.lang.Object f()' of interface user.P.
(g t) ;=> :G
您可以通过宏展开deftype形式来确认一些方法实现被忽略
(macroexpand '(deftype T [] P (f [this] :F) P (g [this] :G)))
;=> (let* [] (deftype* user/T user.T [] :implements [user.P clojure.lang.IType] (g [this] :G)) (clojure.core/import user.T) (clojure.core/defn ->T "Positional factory function for class user.T." [] (new user.T)) user.T)
根本原因似乎归结为parse-impls
(#'clojure.core/parse-impls '(P (f [this] :F) P (g [this] :G)))
;=> {P ((g [this] :G))}
在我看来,如果deftype能够检查是否重复指定了相同的协议,并在重复时抛出错误,那会是件好事。否则,我认为不应该忽视方法实现而不发出任何警告。