如果您在 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 能够检查是否重复指定了相同的协议,并在这种情况抛出错误,那会很好。否则,我认为不应在没有警告的情况下忽略方法实现。