7

我们在不同命名空间中的记录和协议方面存在一些问题。

我们在命名空间 foo.proto 中有一个协议。

(ns foo.proto)

(defprotocol Proto
   (do-stuff [this x y]))

我在命名空间 foo.record 中有一条记录 RecordA:

(ns foo.record
  (:require [foo.proto :as proto]))

(defrecord RecordA [bar])

;; RecordA implements the protocol:

(extend-type RecordA
    proto/Proto
    (do-stuff [this x y] (* x y (:bar this))))

只要我们在 repl 中,它就可以正常工作。现在,如果我们另一方面制作一个 uberjar 并运行我们得到的代码:

没有方法的实现::do-stuff of protocol:#'foo.proto/Proto found for class

另一方面,如果我们像这样在类型声明中实现协议:

(defrecord RecordA [bar]
    proto/Proto
    (do-stuff [this x y] (* x y (:bar this))))

我们不再收到错误(这需要一些时间才能弄清楚)。此外,如果我们将 Proto 的声明移动到与 RecordA 相同的 ns 中,我们也不会收到错误消息。

我的问题:

  1. 在声明中实现和在扩展类型或扩展协议中实现有什么区别?

  2. 如果我们将 Record 和 Protocol 声明移到同一个 ns 中,为什么会起作用?

谢谢

4

3 回答 3

4

问题可能在于您如何在使用它们的文件中包含记录和协议。以下对我有用:

记录.clj

(ns testclojure.record
  (:require [testclojure.proto :as proto]))

(defrecord RecordA [bar])

(extend-type RecordA
  proto/Proto
  (do-stuff [this x y] (* x y (:bar this))))

原型.clj

(ns testclojure.proto)

(defprotocol Proto
  (do-stuff [this x y]))

核心.clj

(ns testclojure.core
  (:require [testclojure.record :refer [->RecordA]]
            [testclojure.proto :refer :all])
  (:gen-class))

(defn -main [& args]
  (-> (->RecordA 2)
      (do-stuff 2 6)
      (println)))

直接运行 jar之后lein uberjar,我得到了 24 的正确答案。

至于为什么它与命名空间和扩展的不同组合一起工作,defrecord创建一个 Java 类,同时在协议集合中extend-type创建一个条目。:impls

于 2013-09-26T03:10:17.050 回答
1

我遇到了类似的问题:

我正在尝试将协议扩展到与协议实现分开定义的记录,即我正在使用(扩展协议)而不是定义与记录内联的实现。Record、协议和实现都在同一个命名空间中。但是,当我尝试调用它时,它抱怨不存在任何实现。

(extend-protocol MyProtocol
  myns.message.Message
 (my-protocol-function [this] (println "got here")))


(my-protocol-function new-msg)

=> IllegalArgumentException No implementation of method: :my-protocol-function of protocol: #'myns.connector/MyProtocol found for class: myns.message.Message  clojure.core/-cache-protocol-fn (core_deftype.clj:544)

但是,如果我查看扩展器,我会在那里看到我的记录

(extenders MyProtocol)
=> (myns.message.Message)

但是(扩展?)是错误的

(extends? MyProtocol myns.message.Message)
=> false

如果我将协议定义内联到记录中,一切都会按预期工作。

于 2014-03-06T20:28:42.990 回答
-2

您需要(:import (foo.proto Proto))foo.record命名空间声明中导入协议。

于 2013-09-24T19:06:58.237 回答