如何使gen-class对象显示更好

时间:2012-09-13 23:46:14

标签: clojure

我有一段代码来实现包含地图的原子地图的参考

 > (def a (example.DynaRec.)

 > (dosync (assoc! a 3 {:id 3 :contents "stuff"} 4 {:id 4}))
 ;;=> #[DynaRec@1a659078: {4 [<Atom@118eb00c: {:id 4}] 3 [Atom@242110fc: {:id 3 :contents "stuff"}]]

我想改变它在repl中显示的方式,以便它只输出

> a 
;;=> ({:id 3 :contents "stuff"}
;;    {:id 4})

怎么办呢?代码如下所示:

(ns example.dyna-rec
  (:gen-class
   :name example.DynaRec
   :prefix "-"
   :init init
   :state state
   :extends clojure.lang.AFn
   :implements [clojure.lang.IDeref
                clojure.lang.Seqable
                clojure.lang.ILookup
                clojure.lang.ITransientMap]))

(defn- $ [this] (:data (.state this)))

(defn- valid?
  ([e]
     (valid? e []))
  ([this e]
     (every? #(contains? e %) (:required (.state this)))))

(defn -deref [this] @($ this))

(defn -valAt
  ([this k] ((-deref this) k nil))
  ([this k nv] 
    (if-let [vatom ((-deref this) k nv)]
      @vatom)))

(defn -invoke
  ([this k] (-valAt this k))
  ([this k nv] -valAt this k nv))

(defn -seq [this] (seq (-deref this)))

(defn -count [this] (count (-deref this)))

(defn -without [this obj]
  (alter ($ this) dissoc obj))

(defn -assoc
  ([this obj] (-assoc this (:id obj) obj))
  ([this k v]
   {:pre [(valid? this v)
          (= k (:id v))]} 
    (alter ($ this) assoc k (atom v))
    this))

(defn -conj [this obj]
  (-assoc this obj))

(defn -persistent [this]
  (-deref this))

(defn -init []
  [[]  {:required  #{:id}
        :data      (ref {})}])

1 个答案:

答案 0 :(得分:5)

要扩展经典的Java模型(clojure包含),你可以实现自己的.toString生成正确的字符串,然后告诉REPL如何正确打印这个新类

首先向dyna-rec.clj添加超级基本toString

(defn- -toString [this]
  (str (into {} this)))

这可以像这样调用:

 (defn- -toString [this]
 (str (zipmap (keys this) (map deref (vals this)))))

example.DynaRec> (.toString a)
"{}"
example.DynaRec> (str a)
"{}"

然后改进打印机以匹配您想要的输出:

(defn- -toString [this]
  (str (zipmap (keys this) (map deref (vals this)))))

并测试它:

example.DynaRec> (str a)
"{3 {:id 3, :contents \"stuff\"}, 4 {:id 4}}"
example.DynaRec> 

这仍然无法在REPL中正确打印,因此我们需要扩展打印机使用的多方法(print-method),REPL使用它来了解您的新类:< / p>

(defmethod print-method 
  example.DynaRec
  [this, w]
  (print-method (zipmap (keys this) (map deref (vals this))) w))

这会产生你想要的东西:

example.DynaRec> a
{3 {:id 3, :contents "stuff"}, 4 {:id 4}}