2013-09-24 2 views
6

Wir haben einige Probleme mit Datensätzen und Protokollen in verschiedenen Namespaces.Clojure-Protokollimplementierung für Datensatztyp in anderem Namensbereich nicht gefunden

Wir haben ein Protokoll im Namespace foo.proto.

(ns foo.proto) 

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

Ich habe einen Rekord recorda im Namensraum foo.record:

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

Dies funktioniert gut, solange wir in den ers sind. Wenn wir nun auf dem Otherhand eine uberjar machen und den Code ausführen, erhalten wir:

Keine Implementierung der Methode: do-Stoff, aus dem Protokoll: # 'foo.proto/gefunden Proto für Klasse

Wenn wir auf der anderen Seite das Protokoll in der Typdeklaration implementieren wie folgt:

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

Wir haben nicht mehr die Fehler (die einige Zeit, um herauszufinden, nahmen). Auch wenn wir die Deklaration von Proto in die gleichen ns wie RecordA verschieben, erhalten wir auch keinen Fehler.

Meine Fragen:

  1. Was ist der Unterschied in der Erklärung zwischen der Umsetzung und in verlängern Typ oder verlängern-Protokoll?

  2. Warum würde es funktionieren, wenn wir die Record- und Protocol-Deklarationen in dieselben ns verschieben?

Dank

Antwort

-2

Sie müssen das Protokoll (:import (foo.proto Proto)) in Ihrer foo.record Namespace-Deklaration importieren.

+0

Nein, das macht keinen Unterschied. –

4

Das Problem kann darin bestehen, wie Sie den Datensatz und das Protokoll in die Datei aufnehmen, in der Sie sie verwenden. Die folgenden Werke für mich:

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

Nach lein uberjar und läuft das Glas direkt, ich die richtige Antwort von 24.

Warum funktioniert es mit verschiedenen Kombinationen von Namespaces und erweitern, defrecord erstellt eine Java-Klasse, während extend-type erstellt einen Eintrag in der :impls Sammlung des Protokolls.

1

ich in laufen lasse, was aussieht wie das gleiche Problem:

Ich versuche, ein Protokoll zu einem Rekord zu verlängern Ich habe getrennt definiert von der Protokollimplementierung, das heißtIch verwende (extend-protocol) anstatt die Implementierung inline mit dem Datensatz zu definieren. Sowohl der Record als auch das Protokoll und die Implementierung befinden sich im selben Namespace. Wenn ich jedoch versuche, es aufzurufen, beschwert es sich, dass keine Implementierung existiert.

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

Allerdings, wenn ich an Extendern anschaue, sehe ich meine Platte dort

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

jedoch (erweitert?) Falsch

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

ist Wenn ich die Protokolldefinition in den Datensatz-line, Alles funktioniert wie erwartet.