代码之家  ›  专栏  ›  技术社区  ›  mikera

Clojure数据结构序列化

  •  17
  • mikera  · 技术社区  · 14 年前

    我有一个复杂的clojure数据结构,我想序列化——基本上是我正在开发的一个在线游戏的整个当前游戏状态,这样我就可以实现保存游戏文件。

    我的要求是:

    • 一些人类可读的文本格式(我可能更喜欢按这个顺序排列的S表达式、JSON和XML,但对其他人开放)
    • 支持所有常见的clojure数据结构、关键字和原语
    • 能够为自定义Java类、FordStand等提供自定义序列化/反序列化功能(这很重要,因为我需要在某些情况下像Java的RealDead那样做)
    • 好的表现是一个很好的拥有

    有什么好的建议吗?

    4 回复  |  直到 12 年前
        1
  •  11
  •   Michał Marczyk    14 年前

    如果要将内容序列化为s表达式,可以使用 print-dup :

    (binding [*print-dup* true] (println [1 2 3]))
    ; prints [1 2 3]
    
    (defrecord Foo [x])
    ; => user.Foo
    (binding [*print-dup* true] (println (Foo. :foo)))
    ; prints #=(user.Foo/create {:x :foo})
    

    请注意,如果打印一个结构(例如,保存对单个向量的十个引用,然后将其读回),则会给您提供一个十个独立的数据结构(而不是 identical? )虽然在结构上相当( = 载体。

    要在没有提供默认实现的情况下使用此方法,请实现多方法 clojure.core/print-dup .

    此外,Clojure 1.2中的许多内容 java.io.Serializable :

    (every? (partial instance? java.io.Serializable)
            [{1 2} #{"asdf"} :foo 'foo (fn [] :foo)])
    ; => true
    
    (defrecord Foo [])
    (instance? java.io.Serializable (Foo.))
    ; => true
    

    请注意,应避免序列化创建的运行时 fn S——它们是具有奇怪名称的一次性类的实例,无论如何,在重新启动JVM之后,您将无法对它们进行反序列化。通过AOT编译, FN S确实有自己固定的类名。

    更新: 正如对这个问题的评论中提到的, Serializable 最适合短期存储/传输数据,而 打印DUP 作为一个长期的存储解决方案(跨应用程序、Clojure等的许多版本工作),应该更加健壮。原因是 打印DUP 在任何方面都不依赖于被序列化的类的结构(因此向量 打印DUP 当向量实现从Java切换到Culjure时,D今天仍然是可读的。 deftype )

        2
  •  7
  •   mikera    12 年前

    edn-format 现在已经作为使用Clojure数据结构进行数据传输的标准发布。

    它非常适合于对Clojure数据结构/值进行序列化,并且支持多种语言,因此也可以用作数据交换格式。

        3
  •  5
  •   G__    14 年前

    如果一切都是clojure数据结构,那么它已经序列化(代码B/C<->数据)。只需将数据结构转储到磁盘上即可。要恢复,请重新加载它们(eval)。

        4
  •  3
  •   Alex Ott    14 年前

    对于JSON,可以使用标准 clojure-contrib.json . 不过,我记得,所有Clojure对象都应该是可序列化的…