【问题标题】:Mixing definterface and defprotocol混合定义接口和定义协议
【发布时间】:2013-08-16 09:13:28
【问题描述】:

我尝试实现表示算术表达式的接口。该接口将由 java 端使用,但整个逻辑都在 clojure 上。

拥有:

(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))))

我尝试将其用作:

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

但我得到了:

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

为什么clojure 会尝试为Expression3 调用ExtendsExpression 的toTree?我希望对于 Expression3 它将调用 Expression 接口的 toTree 方法。

【问题讨论】:

    标签: interface clojure protocols clojure-java-interop java-interop


    【解决方案1】:

    好的,知道了;)

    (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))
    

    并且记录实现了Expression接口,所以我可以很容易地从java中调用它们:

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

    只是为了检查 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}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-14
      • 2011-01-07
      • 2021-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-20
      相关资源
      最近更新 更多