Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Serialization Clojure defrecord序列化类NotFoundException_Serialization_Clojure_Record - Fatal编程技术网

Serialization Clojure defrecord序列化类NotFoundException

Serialization Clojure defrecord序列化类NotFoundException,serialization,clojure,record,Serialization,Clojure,Record,我试图将我的一条记录序列化为人类可读的格式。虽然使用Java serialiser进行序列化工作正常,但我正在尝试使用打印dup。我面临的问题是,在编写记录时,读取clojure.lang.LispReader$ReaderException:java.lang.ClassNotFoundException:common.dummy.Doodh中的记录结果会很顺利。我是不是把名字空间搞砸了? 请注意,这不是Java序列化的问题。 下面以最简单的形式编写代码 (ns common.dummy)

我试图将我的一条记录序列化为人类可读的格式。虽然使用Java serialiser进行序列化工作正常,但我正在尝试使用打印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"]
  • 不要在函数定义中使用def。使用def时,在名称空间中创建一个var,并可能将其作为每个函数调用的副作用进行操作。使用let块

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

  • 使用defrecord定义的类型可以使用
    pr str
    以(Clojure reader-)可读的方式打印(感谢@A.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
        会使代码容易受到slurped文件中函数调用的攻击(如
        #=(java.lang.System/exit 0)
      • 当文件名处的文件为空时,将引发异常
      • 最后,当您将defrecord声明移动到另一个命名空间时,保存的文件将与代码不兼容
      • 使用edn阅读器可以避免所有三个缺点
使用带有EDN的自定义读卡器

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

    (defrecord Doodh [id name]
      Object
      (toString [this] (str "#Doodh" (into {} this))))
    
  • 因为spit使用str,我们现在可以省略输出函数,只需从e调用spit。G答复:

    (spit "Doodh.edn" (map->Doodh {:id "134" :name "Berta"}))
    
    (pull "Doodh.edn")
    => #user.Doodh{:id 134, :name "Berta"}
    
    Doodh.edn: #Doodh{ID134,:name“Berta”}

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

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

    (spit "Doodh.edn" (map->Doodh {:id "134" :name "Berta"}))
    
    (pull "Doodh.edn")
    => #user.Doodh{:id 134, :name "Berta"}
    

  • 顺便问一下,什么是Doodh?不能重现错误。报告`*clojure版本*和生成异常的测试。Doodh=Milk。因此moohs和cows.@A.Webb-Webb-Clojure版本{:major 1,:minor 5,:incremental 1,:qualifier nil}。不太确定是否相关,但我使用的是ring、lacij、tikkba。正如我在前面提到的,当我在做一个纯粹的基于Java的序列化时,这种方法可以很好地工作。请注意名称空间。我报告的错误不是来自repl,您的答案所指的是哪个`*clojure版本*?我想你的第三点可能已经过时了。你是在暗示它会自动为#user.Doodh选择一个读卡器fn吗?哦,你指的是
    edn
    读卡器?否,但将调用构造函数。短语“不能以(Clojure reader-)可读的方式打印”是一种混淆。换句话说,
    (带有in-str(pr-str(common.dummy.Doodh.foo“bar”))(Clojure.core/read))
    是Clojure阅读器,工作正常。但是,是的,
    (带in-str(pr-str(common.dummy.Doodh.foo”“bar))(clojure.edn/read))
    会抱怨edn没有读卡器功能。非常感谢您的澄清。我不知道Clojure阅读器能够读回打印的记录。我会更新我的答案。