2013-08-01 33 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-)可讀的方式打印」這個短語是混亂。 –

相關問題