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: #'foo.proto/クラスの Proto が見つかりました

一方、次のように型宣言でプロトコルを実装するとします。

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

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

jar を直接実行した後lein uberjar、24 の正しい答えが得られます。

名前空間と拡張のさまざまな組み合わせで機能する理由については、プロトコルのコレクションにエントリを作成しdefrecordながら、Java クラスを作成します。extend-type:impls

于 2013-09-26T03:10:17.050 に答える
1

私は同じ問題のように見えるものに遭遇しています:

プロトコルの実装とは別に定義したレコードにプロトコルを拡張しようとしています。つまり、レコードとインラインで実装を定義するのではなく、(extend-protocol) を使用しています。レコード、プロトコル、および実装の両方が同じ名前空間にあります。ただし、それを呼び出そうとすると、実装が存在しないと不平を言います。

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

ただし、(拡張?) は false

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

プロトコル定義をレコードにインライン化すると、すべてが期待どおりに機能します。

于 2014-03-06T20:28:42.990 に答える