这里我有一个循环引用列表
2.1.9 :082 > a = []
=> []
2.1.9 :083 > a.append(a)
=> [[...]]
当尝试将a
转储为json时,我收到错误
a.to_json
ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself
但是当我尝试Marshal他们时,我得到一个有效的字符串
2.1.9 :085 > Marshal.dump(a)
=> "\x04\b[\x06@\x00"
我只是试图确保他们通过再次加载来正确地转储价值
b = Marshal.load("\x04\b[\x06@\x00")
=> [[...]]
以下是一些更多验证,以确保它们正确地将对象转储到字符串
2.1.9 :088 > a.object_id
=> 70257482733700
2.1.9 :089 > a.first.object_id
=> 70257482733700
2.1.9 :090 > b.object_id
=> 70257501553000
2.1.9 :091 > b.first.object_id
=> 70257501553000
2.1.9 :092 >
据我所知,他们都将对象转换为字符串并从字符串中取回对象。我还能看到json没有任何构造来引用json的其他部分,这可能是它不能支持这种操作的原因。但是,在json中引入这样的结构是否很难以促进当前的情况。我可能会遗漏一些关于编组和序列化的更重要的事情,请赐教。
答案 0 :(得分:3)
在我的理解中,他们都将对象转换为字符串并从字符串中取回对象。
是。这几乎是"序列化"的定义。或"编组"。
我还能看到json没有任何构造来引用json的其他部分,这可能是它无法支持这种操作的原因。
是的,这就是原因。
但是在json中引入这样的结构是否难以促进目前的情况。
您无法在JSON中介绍构造。它被故意设计为没有版本号,因此它永远不会被改变。
当然,这只意味着我们现在无法添加 ,但是Doug Crockford可以从一开始就将添加到,当他设计JSON时?当然是。但他没有。 JSON was deliberately designed to be simple (bold emphasis mine):
JSON不是文档格式。它不是标记语言。它甚至不是一般的序列化格式,因为它没有直接表示循环结构 [...]
例如,参见YAML,它是JSON的超集,它具有引用,因此可以表示循环数据。
答案 1 :(得分:1)
Marshal.dump
和to_json
都返回一个字符串,但这是关于他们共同拥有的所有内容。
to_json
根据JSON specifications返回描述Ruby对象的String。
to_json
进行修补,当在一个数组上调用时,它在每个元素上都被称为recursively:
"[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ','}]"
这种递归是你得到的原因:
ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself
如果导出成功,则可以通过新的Rubinius脚本读取在旧的JRuby on Rails服务器或PHP服务器上编写的JSON字符串。
Marshal.dump
返回一个字节流,表示对象本身,以及Ruby如何在内部存储它:
Marshal.dump(a).bytes
#=> [4, 8, 91, 6, 64, 0]
Marshal.dump([[]]).bytes
#=> [4, 8, 91, 6, 91, 0]
Marshal.dump([]).bytes
#=> [4, 8, 91, 0]
因此Marshal.dump
存储a
已定义:一个元素数组,引用自身。
前两个字节是主要版本号和次要版本号。将转储对象与相同版本进行比较时,可以使用以下命令忽略它们:
Marshal.dump(a).bytes.drop(2)
#=> [91, 6, 64, 0]
Marshal.dump([[]]).bytes.drop(2)
#=> [91, 6, 91, 0]
由于表示依赖于Ruby实现,因此从一个Ruby脚本转储到另一个Ruby脚本可能并不总是有效。
来自doc:
在正常使用中,编组只能加载用相同的数据写入的数据 主要版本号和相等或较低的次要版本号。