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

为什么封送处理可以序列化循环引用列表,而json不能?,json,ruby,serialization,marshalling,circular-reference,Json,Ruby,Serialization,Marshalling,Circular Reference,这里我有一个循环引用列表 2.1.9 :082 > a = [] => [] 2.1.9 :083 > a.append(a) => [[...]] 当我试图将一个文件转储为json时,我得到了一个错误 a.to_json ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself 但是当我试图封送它们时,我得到了一个有效的字符串 2.1.9 :085 >

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

2.1.9 :082 > a = []
 => [] 
2.1.9 :083 > a.append(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.dump和to_json都返回字符串,但这就是它们的共同点

到u json to_json根据json返回一个描述Ruby对象的字符串

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

"[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ','}]"
这种递归是您得到以下结果的原因:

ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself
如果导出成功,新Rubinius脚本可以读取在旧JRuby on Rails服务器或PHP服务器上编写的JSON字符串

倾倒 返回一个字节流,表示对象本身,以及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按定义存储一个数组:一个引用自身的单元素数组

前两个字节是主版本号和次版本号。将转储对象与相同版本进行比较时,可以通过以下方式忽略它们:

Marshal.dump(a).bytes.drop(2)
#=> [91, 6, 64, 0]
Marshal.dump([[]]).bytes.drop(2)
#=> [91, 6, 91, 0]
因为表示依赖于Ruby实现,所以从一个Ruby脚本转储到另一个可能并不总是有效的

从:

在正常使用情况下,封送处理只能加载使用相同的文件写入的数据 主要版本号和相等或更低的次要版本号

Marshal.dump和to_json都返回一个字符串,但这就是它们的共同点

到u json to_json根据json返回一个描述Ruby对象的字符串

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

"[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ','}]"
这种递归是您得到以下结果的原因:

ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself
如果导出成功,新Rubinius脚本可以读取在旧JRuby on Rails服务器或PHP服务器上编写的JSON字符串

倾倒 返回一个字节流,表示对象本身,以及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按定义存储一个数组:一个引用自身的单元素数组

前两个字节是主版本号和次版本号。将转储对象与相同版本进行比较时,可以通过以下方式忽略它们:

Marshal.dump(a).bytes.drop(2)
#=> [91, 6, 64, 0]
Marshal.dump([[]]).bytes.drop(2)
#=> [91, 6, 91, 0]
因为表示依赖于Ruby实现,所以从一个Ruby脚本转储到另一个可能并不总是有效的

从:

在正常使用情况下,封送处理只能加载使用相同的文件写入的数据 主要版本号和相等或更低的次要版本号

据我所知,他们都在将一个对象转换为字符串,并从字符串中取回该对象

对。这几乎就是序列化或封送处理的定义

我还可以看到json没有任何引用json其他部分的构造,这可能是它无法支持此类操作的原因

是的,这就是原因

但是,在json中引入这样的构造来促进当前的情况是否有那么困难呢

不能在中引入构造。它被故意设计成没有版本号,所以它永远不会被改变

当然,这只意味着我们现在不能添加它,但是Doug Crockford是否可以从一开始就添加它,回到他设计JSON的时候?当然可以。但他没有:

JSON不是文档格式。它不是一种标记语言。它甚至不是一般的序列化格式,因为它没有循环结构的直接表示[…]

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

据我所知,他们都在将一个对象转换为字符串,并从字符串中取回该对象

对。这几乎就是序列化或封送处理的定义

我还可以看到json没有任何引用json其他部分的构造,这可能是它无法支持此类操作的原因

是的,这就是原因

但是,在json中引入这样的构造来促进当前的情况是否有那么困难呢

不能在中引入构造。它被故意设计成没有版本号,这样它就永远不会有b 我变了

当然,这只意味着我们现在不能添加它,但是Doug Crockford是否可以从一开始就添加它,回到他设计JSON的时候?当然可以。但他没有:

JSON不是文档格式。它不是一种标记语言。它甚至不是一般的序列化格式,因为它没有循环结构的直接表示[…]

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