david4dev 对 this Question 的回答声称,使用
json
库可以使用三种等效方法将对象转换为 JSON 字符串:
JSON.dump(object)
JSON.generate(object)
object.to_json
以及将 JSON 字符串转换为对象的两种等效方法:
JSON.load(string)
JSON.parse(string)
但是看源代码,它们每个似乎都有很大不同,并且它们之间存在一些差异(例如,1)。
它们之间有什么区别?什么时候用哪个?
TL;博士:
总体来说:
to_json
(或等效的 JSON::generate
)。JSON::parse
。对于某些特殊用例,您可能需要
dump
或 load
,但在不是您自己创建的数据上使用 load
是不安全的。
扩展说明:
JSON::dump
vsJSON::generate
作为其参数签名的一部分,
JSON::generate
允许您设置缩进级别和空白细节等选项。另一方面,JSON::dump
在其内部调用 ::generate
,并具有特定的预设选项,因此您无法自行设置这些选项。
根据文档,
JSON::dump
旨在成为Marshal::dump
实施方案的一部分。您想要自己显式使用 ::dump
的主要原因是您将要传输 JSON 数据(例如通过套接字),因为 ::dump
允许您传递类似 IO 的对象作为第二个参数。不幸的是,生成的 JSON 数据并没有像生成时那样真正进行流式传输;它是集体创建的,并且仅在 JSON 完全创建后才发送。这使得 IO 参数仅在微不足道的情况下有用。
两者之间的最后一个区别是 ::dump
还可以接受
limit
参数,当超出一定的嵌套深度时,它会引发 ArgumentError。
#to_json
#to_json
接受选项作为参数,因此
JSON::generate(foo, opts)
和 foo.to_json(opts)
基本上是等价的。内部实现不同,这可能会导致令人惊讶的效果(请参阅评论)。
JSON::load
vs
JSON::parse
类似于 ::dump
在内部调用
::generate
,::load
在内部调用 ::parse
。 ::load
,与::dump
一样,也可能采用 IO 对象,但同样,源是一次性读取的,因此流仅限于简单的情况。然而,与 ::dump
/::generate
对偶不同,::load
和 ::parse
都接受选项作为其参数签名的一部分。::load
也可以传递一个 proc,它将在从数据解析的每个 Ruby 对象上调用;它还附带一个警告,即
::load
只能与可信数据一起使用。 ::parse
没有这样的限制,因此JSON::parse
是解析不受信任的数据源(例如用户输入和具有未知内容的文件或流)的正确选择。