简体   繁体   English

混合definterface和defprotocol

[英]Mixing definterface and defprotocol

I try to implement interface representing arithmetic expressions. 我尝试实现表示算术表达式的接口。 The interface will be used by java-side but the whole logic is on clojure. 接口将由java端使用,但整个逻辑在clojure上。

Having: 有:

(defprotocol ExtendsExpression
  (toTree [this]))

(extend-type String
  ExtendsExpression
  (toTree [this] (symbol this)))

(extend-type Number
  ExtendsExpression
  (toTree [this] this))

(definterface Expression
  (toTree []))

(defrecord Expression1 [^String oper arg]
  Expression
  (toTree [this]
    (list (symbol oper) (toTree arg))))


(defrecord Expression2 [^String oper arg1 arg2]
  Expression
  (toTree [this]
    (list (symbol oper) (toTree arg1) (toTree arg2))))

(defrecord Expression3 [^String oper arg1 arg2 arg3]
  Expression
  (toTree [this]
    (list (symbol oper) (toTree arg1) (toTree arg2) (toTree arg3))))

I try to use it as: 我试着用它作为:

(toTree (Expression3. "+" "a" "b" (Expression2. "*" "c" "d")))

but I'm getting: 但我得到了:

IllegalArgumentException No implementation of method: :toTree of protocol: #'user/ExtendsExpression found for class: user.Expression3  clojure.core/-cache-protocol-fn (core_deftype.clj:541)

Why clojure tries to call toTree of ExtendsExpression for Expression3? 为什么clojure试图为Expression3调用toTree of ExtendsExpression? I expect that for Expression3 it will call the toTree method of Expression interface. 我希望对于Expression3,它将调用Expression接口的toTree方法。

Ok, Got it ;) 好的,我知道了 ;)

(defprotocol ExtendsExpression
  (to-tree [this]))

(extend-type String
  ExtendsExpression
  (to-tree [this] (symbol this)))

(extend-type Number
  ExtendsExpression
  (to-tree [this] this))

(definterface Expression
  (toTree []))

(defrecord Expression1 [^String oper arg]
  ExtendsExpression
  (to-tree [this]
    (list (symbol oper) (to-tree arg)))
  Expression
  (toTree [this] (to-tree this)))


(defrecord Expression2 [^String oper arg1 arg2]
  ExtendsExpression
  (to-tree [this]
    (list (symbol oper) (to-tree arg1) (to-tree arg2)))
  Expression
  (toTree [this] (to-tree this)))

(defrecord Expression3 [^String oper arg1 arg2 arg3]
  ExtendsExpression
  (to-tree [this]
    (list (symbol oper) (to-tree arg1) (to-tree arg2) (to-tree arg3)))
  Expression
  (toTree [this] (to-tree this)))

(to-tree (Expression3. "+" "a" "b" (Expression2. "*" "c" "d"))) ;=> (+ a b (* c d))

and the records implements Expression interface, so I can call them from java easily: 并且记录实现了Expression接口,因此我可以轻松地从java中调用它们:

(.toTree (Expression3. "+" "a" "b" (Expression2. "*" "c" "d"))) ;=> (+ a b (* c d))

just to check what interfaces Expression3 implements: 只是为了检查Expression3实现的接口:

 (-> Expression3 clojure.reflect/reflect :bases pprint)
#{clojure.lang.IHashEq java.io.Serializable clojure.lang.IKeywordLookup
  clojure.lang.IPersistentMap clojure.lang.IRecord java.lang.Object
  user.ExtendsExpression clojure.lang.IObj clojure.lang.ILookup
  user.Expression java.util.Map}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM