3

レコードの 1 つを人間が読める形式にシリアル化しようとしていました。Javaシリアライザーを使用したシリアライズは正常に機能しましたが、print-dupを使用しようとしています。私が直面している問題は、レコードの書き込みは正常に行われますが、レコードの読み取りが clojure.lang.LispReader$ReaderException: java.lang.ClassNotFoundException: common.dummy.Doodh になることです。名前空間か何かを台無しにしていますか? これは Java シリアライゼーションの問題ではないことに注意してください。以下の最も単純な形式のコード

(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"]
4

1 に答える 1

6
  • 関数定義内で def を使用しないでください。def を使用しているときは、名前空間に var を作成し、すべての関数呼び出しの副作用としてそれを操作する可能性があります。let ブロックを使用します。

  • Clojure のデータ構造をファイルに保存する場合は、clojure.edn. これは安全ですが (たとえば、知らないうちにファイルで定義された関数が呼び出されることはありません)、カスタム リーダーを有効にすることができます (詳細は以下を参照)。

  • defrecord で定義された型は、(Clojure リーダーが) 読み取り可能な方法で出力できます (@A pr-str. Webb に感謝します)。あなたの例では、そもそもハッシュマップに固執しない理由がわかりませんが、ここで defrecord が本当に必要な場合は、ファイルに書き込む前に読み取り可能な文字列に変換できます。

    (defrecord Doodh [id name])
    
    (defn output [filename obj]
      (spit filename (pr-str obj))
    
    (defn pull [filename]
      (with-in-str (slurp filename)
                   (read)))
    
    • この方法には、いくつかの欠点があります。
      • を使用readすると、丸呑みされたファイル ( など) での関数呼び出しに対してコードが脆弱になります#=(java.lang.System/exit 0)
      • filename のファイルが空の場合、例外がスローされます。
      • 最後に、defrecord 宣言を別の名前空間に移動すると、保存したファイルはコードと互換性がなくなります。
      • edn-reader を使用すると、3 つの欠点をすべて回避できます。

EDN でのカスタム リーダーの使用

  1. java.lang.Object インターフェイスの toString メソッドを実装することで、型 Doodh を拡張します。

    (defrecord Doodh [id name]
      Object
      (toString [this] (str "#Doodh" (into {} this))))
    
  2. spit は str を使用するため、出力関数を省略して、REPL などから単純に spit を呼び出すことができます。

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

    Doodh.edn: #Doodh{:id 134, :name "ベルタ"}

  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"}
    
于 2013-08-01T11:34:05.857 に答える