Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/371.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
Java Clojure数据结构序列化_Java_Serialization_Clojure - Fatal编程技术网

Java Clojure数据结构序列化

Java Clojure数据结构序列化,java,serialization,clojure,Java,Serialization,Clojure,我有一个复杂的Clojure数据结构,我想序列化它-基本上是我正在开发的在线游戏的整个当前游戏状态,这样我就可以实现保存游戏文件 我的要求是: 某种形式的人类可读文本格式(我可能更喜欢s表达式、JSON和XML的顺序,但对其他人开放) 支持所有常用的Clojure数据结构、关键字和原语 能够为自定义java类、defrecords等提供自定义序列化/反序列化函数(这一点很重要,因为在某些情况下我需要像java的readResolve那样做) 良好的性能是一个很好的选择 有什么好的建议吗?对于

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

我的要求是:

  • 某种形式的人类可读文本格式(我可能更喜欢s表达式、JSON和XML的顺序,但对其他人开放)
  • 支持所有常用的Clojure数据结构、关键字和原语
  • 能够为自定义java类、defrecords等提供自定义序列化/反序列化函数(这一点很重要,因为在某些情况下我需要像java的readResolve那样做)
  • 良好的性能是一个很好的选择

有什么好的建议吗?

对于JSON,您可以使用标准。虽然,正如我所记得的,所有Clojure对象都应该是可序列化的…

如果一切都是Clojure数据结构,那么它已经序列化了(代码数据的b/c)。只需将数据结构转储到磁盘上。要恢复,请将它们加载回(eval)。

如果要将内容序列化为S表达式,可以使用
打印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})
请注意,打印一个包含(比如)对单个向量的十个引用的结构,然后再将其读回,将得到一个包含十个独立(不完全相同?)向量的数据结构,尽管在结构(
=
)向量方面是等效的

要在没有提供默认实现的情况下使用此方法,请实现multi-method
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
最适合于数据的短期存储/传输,而
print dup
作为长期存储解决方案应该更健壮(跨多个版本的应用程序、Clojure等)。原因是
print dup
在任何方面都不依赖于被序列化的类的结构(因此,当向量实现从Java切换到Clojure的
deftype
时,今天的向量
print dup
'd仍然是可读的).

现已作为使用Clojure数据结构进行数据传输的标准发布


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

不太了解Clojure,使用Clojure调用的标准Java序列化机制无法实现这一点,有什么原因吗?@Gian-是的,这当然是可能的,但我正在尝试学习“Clojure方式”做事情:-)在我看来,Clojure方式是使用Java的设施,为解决问题提供良好的解决方案。:-)<代码>可序列化对于数据结构的短期存储/传输来说可能是一个很好的解决方案。话虽如此,我想对于这个用例,需要一种更适合长期存储的格式,这可能是由
print dup
提供的。(
Serializable
如果实现核心Clojure数据结构的类的结构发生变化,可能会遇到问题;
print dup
可能不会)尝试了这个,它不喜欢我的Java类:它抛出例如Java.lang.Exception:不知道如何编写mikera.persistent.SparseMap类的JSON。有没有办法为您自己的类提供自定义序列化函数?您可以让您的类实现
clojure.contrib.json.Write_json
接口(或者协议
clojure.contrib.json/Write json
,如果类是clojure记录/类型)。不过,我不知道你会怎么把它们读回来;我认为对于非标准数据结构,您应该使用类似YAML的东西。快速的Google搜索发现
clj yaml
是一个可能的解决方案,尽管我对这个项目一无所知。啊,刚刚注意到
clj yaml
的自述文件说它现在只支持反序列化…我想
print dup
可能是这个用例的最佳解决方案,见我对这个问题的评论。。。如果保存的游戏可能变大,打印输出总是可以压缩的。将
*out*
绑定到一个文件流,然后使用
(pr)
(然后使用
(加载文件)
将其读回)。请参阅一个工作示例。评估它们是否危险?有人可能会在里面偷偷藏一些代码。我相信它们应该被阅读,但不应该被评估。这是任何序列化都要考虑的问题。如果未计算,则必须添加整个读取/解析层。如果这是一个不受信任的用户可以访问文件的情况,那么我想我更愿意将其扩展一点,并放入加密层或散列。这对核心Clojure数据结构很有效,但假设您在其中有一个更奇特的数据结构,如PriorityMap(它看起来就像PersistentMap,但行为不同),然后你需要使用读卡器宏或其他什么,对吗?它们在edn格式中有这样的想法:你可以“标记”值以指示它们是一种特殊类型,并编写自己的处理程序来构造适当的类。真是太棒了!