3

我试图将我的一个记录序列化为人类可读的格式。虽然使用 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,并可能将其作为每个函数调用的副作用进行操作。使用让块。

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

  • pr-str使用 defrecord 定义的类型可以使用(感谢@A. Webb 注意到)以(Clojure-reader-)可读方式打印。在您的示例中,我不明白为什么您首先不坚持使用哈希映射,但是如果您真的需要在这里使用 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 可以避免所有三个缺点。

使用带有 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 "Berta"}

  3. 现在为了确保 Doodh 将被读回,我们clojure.edn/read-string使用自定义读取器函数调用:

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

    (pull "Doodh.edn")
    => #user.Doodh{:id 134, :name "Berta"}
    
于 2013-08-01T11:34:05.857 回答