2013-02-22 2 views
5

У меня есть класс Java Vector2, который я хотел бы убедить «отлично играть» с читателем Clojure.Кругооборот Java-класса через принтер и считыватель Clojure

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

В идеале я хотел бы класс, чтобы распечатать в форме, которая может быть прочитана читателем Clojure. то есть я хотел следующий вернуться верно:

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

Что является лучшим способом достижения этого кругооборота возможности?

+0

Вы не хотите привлекать к 'EvalReader', я полагаю? –

+0

@Marko: открыт для предложений. Он специально не предназначен для внешнего API - для удобства в REPL и простой сериализации/десериализации. – mikera

+0

Я думаю, что с 'read-eval' осталось до истины, читатель будет знать, что делать с' # = (Vector2. 1 2) '. –

ответ

5

Для вашего класса/типа вам необходимо предоставить print-dup и print-method мультиметоды.

Заканчивать 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

Это, кажется, охватывает только конец письма. Как он читает? –

+0

'read-string' для чтения. В основном этот мультиметод будет возвращать s-выражение в строчном формате, таком как '(vec2 1 2)', что при выполнении результата в создании желаемого объекта – Ankur

+0

Это не то, что хочет Mikera: он не хочет «eval» код в его объект; он хочет ** прочитать ** это, как родной вектор Clojure. –