【问题标题】:Clojure Protocol Implementation not Found for Record Type in other namespace在其他命名空间中找不到记录类型的 Clojure 协议实现
【发布时间】:2013-09-24 15:11:29
【问题描述】:

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

我们在命名空间 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 中,为什么会起作用?

谢谢

【问题讨论】:

    标签: clojure protocols records


    【解决方案1】:

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

    record.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))))
    

    proto.clj

    (ns testclojure.proto)
    
    (defprotocol Proto
      (do-stuff [this x y]))
    

    core.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)))
    

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

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

    【讨论】:

      【解决方案2】:

      我遇到了类似的问题:

      我正在尝试将协议扩展到我定义的与协议实现分开的记录,即我正在使用 (extend-protocol) 而不是定义与记录内联的实现。 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
      

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 不,没有区别。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多