2013-02-22 2 views
5

Ho una classe Java Vector2 che mi piacerebbe convincere a "giocare bene" con il lettore Clojure.Rotazione di una classe Java tramite la stampante e il lettore Clojure

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

Idealmente mi piacerebbe la classe di stampare in una forma che può essere letto dal lettore Clojure. cioè mi piacerebbe quanto segue per restituire true:

(= a (read-string (print-str a))) 

Qual è il modo migliore per raggiungere questa capacità round-intervento?

+0

Non si vuole coinvolgere il 'EvalReader', suppongo? –

+0

@ Marko: aperto ai suggerimenti. Non è specificamente concepito per un'API esterna - più per comodità al REPL e facile serializzazione/deserializzazione. – mikera

+0

Penso che con 'read-eval' lasciato a true, il lettore saprà cosa fare con' # = (Vector2. 1 2) '. –

risposta

5

È necessario fornire i metodi multimetro print-dup e print-method per la classe/tipo.

Partenza core.clj

Es:

(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

Questo sembra coprire solo la fine della scrittura. Come si legge? –

+0

'read-string' è per la lettura. Fondamentalmente questo multimethod restituirà un'espressione s in formato di stringa come '(vec2 1 2)' che quando viene eseguito genera nella creazione dell'oggetto desiderato – Ankur

+0

Questo non è ciò che vuole Mikera: non vuole "rivalutare" il codice in il suo oggetto; vuole ** leggere **, proprio come un vettore Clojure nativo. –