为什么封送处理可以序列化循环引用列表而 json 不能?

Why marshaling can serialize circular referenced list and json can't?

这里我有一个循环引用列表

2.1.9 :082 > a = []
 => [] 
2.1.9 :083 > a.append(a)
 => [[...]] 

尝试将 a 转储为 json 时,出现错误

a.to_json
ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself

但是当我尝试编组它们时,我得到了一个有效的字符串

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 中引入这样的结构来促进当前的情况是不是很困难。我可能遗漏了一些关于编组和序列化的更基本的东西,请赐教。

Marshal.dumpto_json return 都是一个字符串,但这就是它们的所有共同点。

to_json

to_json returns 根据 JSON specifications.

描述 Ruby 对象的字符串

to_json 基本上需要在每个可能的 Ruby 对象上进行猴子修补,并且在数组上调用时,它会在每个元素上调用 recursively :

"[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ','}]"

这个递归是你得到的原因:

ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself

如果导出成功,在Rails服务器或PHP服务器上的旧JRuby上写入的JSON字符串可以被新的Rubinius读取脚本。

转储

Marshal.dump returns 一个字节流,表示对象本身,以及它在内部的存储方式 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 脚本转储到另一个脚本可能并不总是有效。

来自doc :

In normal use, marshaling can only load data written with the same major version number and an equal or lower minor version number.

In my understanding both of them are converting an object to string and get the object back from the string.

是的。这几乎就是 "serialization" 或 "marshaling".

的定义

I also able to see that json don't have any construct to refer other part of the json which may be the reason why it can't support this kind of operation.

是的,就是这个原因。

But is it that difficult to introduce such construct in json to facilitate the current situation.

您不能在 JSON 中引入结构。它被特意设计为没有版本号,因此永远无法更改。

当然,这仅意味着我们现在无法添加它,但 Doug Crockford 是否可以添加它从一开始,返回他在设计的时候JSON?是的当然。但他没有。 JSON was deliberately designed to be simple (bold emphasis mine):

JSON is not a document format. It is not a markup language. It is not even a general serialization format in that it does not have a direct representation for cyclical structures […]

参见,例如,YAML,JSON 的超集,它具有引用,因此可以表示循环数据。