我有一段代码来实现包含地图的原子地图的参考
> (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 {})}])
答案 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}}