2013-08-01 31 views
3

我试图将我的一个记录序列化为人类可读的格式。虽然使用Java序列化程序的序列化工作正常,但我试图使用print-dup。我面临的问题是,在写入记录的过程中,读取记录的结果会很好,只需读取clojure.lang.LispReader $ ReaderException:java.lang.ClassNotFoundException:common.dummy.Doodh。我搞砸了命名空间还是什么? 请注意,这不是Java序列化的问题。下面 代码最简单的形式Clojure defrecord序列化ClassNotFoundException

(ns common.dummy) 

    (defrecord Doodh [id name]) 

    (defn output [filename obj] 
    (def trr(map->Doodh {:id "moooh" :name "Cows"})) 
    (def my-string (binding [*print-dup* true] (pr-str trr))) 
    (spit filename my-string) 
    ) 

    (defn pull [filename] 
    (def my-data (with-in-str (slurp filename) (read))) 
    (println my-data) 
    ) 

文本文件的内容:

#common.dummy.Doodh["moooh", "Cows"] 
+1

什么是Doodh,顺便说一下? –

+0

无法重现错误。报告'* clojure-version *和你生成异常的测试。 –

+1

Doodh =牛奶。因此,mooh和奶牛。 – Cyrax

回答

6
  • 不要内部函数定义高清使用。当你使用def时,你在你的命名空间中创建一个var,并且可能在每次函数调用时都将它作为一个副作用进行操作。使用let-blocks。

  • 如果要将Clojure数据结构保存在文件中,请使用clojure.edn。这是安全的(例如,在你不知情的情况下,文件中定义的任何函数都不会被调用),但它允许启用自定义阅读器(请参阅下面的更多内容)。

  • 使用pr-str(感谢@A。Webb注意到),可以以(Clojure-reader-)可读的方式打印使用defrecord定义的类型。在你的例子中,我不明白为什么你不会坚持哈希映射,但如果你真的需要这里的defrecord,你可以在将它写入文件之前将它转换成可读的字符串。

    (defrecord Doodh [id name]) 
    
    (defn output [filename obj] 
        (spit filename (pr-str obj)) 
    
    (defn pull [filename] 
        (with-in-str (slurp filename) 
           (read))) 
    
    • 做的这种方式有几个缺点。
      • 使用read会使您的代码容易受到slurped文件中的函数调用(如#=(java.lang.System/exit 0))的影响。
      • 当filename处的文件为空时,将引发异常。
      • 最后,当您将defrecord声明移动到另一个名称空间时,您保存的文件将与您的代码不兼容。
      • 所有这三个缺点都可以通过使用edn-reader来避免。

        (defrecord Doodh [id name] 
            Object 
            (toString [this] (str "#Doodh" (into {} this)))) 
        

使用自定义读者EDN

  1. 我们通过实现java.lang.Object中接口的toString方法扩展我们的类型Doodh

  2. 因为spit使用str,w e现在可以省略输出函数,并简单地从e中调用spit。 G。在REPL:

    (spit "Doodh.edn" (map->Doodh {:id "134" :name "Berta"})) 
    

    Doodh。EDN: #Doodh {:编号134:名 “贝尔塔”}

  3. 我们确保该Doodh将被读取的时候,我们调用clojure.edn/read-string使用自定义读卡器功能:

    (defn pull [filename] 
        (->> (slurp filename) 
         (clojure.edn/read-string {:readers {'Doodh map->Doodh}}))) 
    
  4. 如果您使用新拉回读“Doodh.edn”,您应该收到一个有效的Doodh。在REPL:

    (pull "Doodh.edn") 
    => #user.Doodh{:id 134, :name "Berta"} 
    
+0

你的答案指的是哪个'* clojure-version *?我认为你的第三点可能已经过时了。 –

+0

1.5.1。你是否暗示它会自动为#user.Doodh选择一个reader-fn? –

+1

哦,你指的是'edn'阅读器?不,但[Clojure reader](http://clojure.org/reader)将调用构造函数。 “不能用(Clojure-reader-)可读的方式打印”这个短语是混乱。 –

相关问题