2013-02-22 4 views
5

Ich habe eine Java-Klasse Vector2, die ich gerne überreden würde, "schön" mit dem Clojure-Leser zu spielen.Round-tripping eine Java-Klasse durch den Clojure-Drucker und Leser

(def a (vec2 1 2)) 
(print-str a) 
=> "#<Vector2 [1 2]>" 

Idealerweise möchte ich, dass die Klasse in einer Form ausgedruckt wird, die vom Clojure-Leser gelesen werden kann. d. ich möchte, dass das Folgende wahr ergibt:

Was ist der beste Weg, um diese Rundauslösefähigkeit zu erreichen?

+0

Sie wollen nicht die 'EvalReader' einzubeziehen, nehme ich an? –

+0

@Marko: Offen für Vorschläge. Es ist nicht speziell für eine externe API gedacht - mehr für die Bequemlichkeit bei der REPL und einfache Serialisierung/Deserialisierung. – mikera

+0

Ich denke mit 'read-eval' links zu true, wird der Leser wissen, was mit' # = (Vector2. 1 2) 'zu tun ist. –

Antwort

5

Sie müssen print-dup und print-method Multimethoden für Ihre Klasse/Typ angeben.

Check out core.clj

Ex:

(import 'java.util.Hashtable) 
(defmethod print-method Hashtable [x writer] 
     (binding [*out* writer] 
     (print (let [h (gensym)] 
       `(let [~h (Hashtable.)] 
        [email protected](map (fn [i] 
           `(.put ~h ~(str "\"" (.getKey i) "\"") ~(.getValue i) )) x) ~h))) )) 
(def a (Hashtable.)) 
(.put a "a" 1) 
(.put a "b" 2) 
(= a (eval (read-string (print-str a)))) 
+0

Dies scheint nur das Schreibende zu decken. Wie macht es Lesen? –

+0

'read-string' dient zum Lesen. Im Grunde liefert diese Multimethode einen s-Ausdruck im String-Format wie '(vec2 1 2)', der bei der Ausführung das gewünschte Objekt erzeugt. – Ankur

+0

Das ist nicht das, was Mikrona will: er will den Code nicht 'einlesen' sein Objekt; er möchte es lesen, genau wie ein einheimischer Clojure-Vektor. –