这是我的第一个问题,我已经尽力找到答案 - 我已经到处寻找答案,但在oj docs和ruby json docs以及这里找不到任何具体的答案。
Oj是一个用于提高序列化/反序列化速度的gem,可在以下位置找到:https://github.com/ohler55/oj
当我尝试转储并解析包含在其中的NaN的哈希值两次时,我注意到了这种差异,并将两者进行了比较,即
# Create json Dump
dump = JSON.dump ({x: Float::NAN})
# Create first JSON load
json_load = JSON.parse(dump, allow_nan: true)
# Create second JSON load
json_load_2 = JSON.parse(dump, allow_nan: true)
# Create first OJ load
oj_load = Oj.load(dump, :mode => :compat)
# Create second OJload
oj_load_2 = Oj.load(dump, :mode => :compat)
json_load == json_load_2 # Returns true
oj_load == oj_load_2 # Returns false
我一直认为NaN无法与NaN进行比较所以这让我困惑了一段时间,直到我意识到json_load和json_load_2具有相同的对象ID而oj_load和oj_load_2没有。
有人能指出我的内存分配/对象ID分配发生的方向,或者我如何用OJ控制这种行为?
非常感谢和抱歉,如果这个答案在互联网上的某个地方浮动,我找不到它。
其他信息: 我正在运行Ruby 1.9.3。
以下是我的测试对象ID的输出:
puts Float::NAN.object_id; puts JSON.parse(%q({"x":NaN}), allow_nan: true)["x"].object_id; puts JSON.parse(%q({"x":NaN}), allow_nan: true)["x"].object_id
70129392082680
70129387898880
70129387898880
puts Float::NAN.object_id; puts Oj.load(%q({"x":NaN}), allow_nan: true)["x"].object_id; puts Oj.load(%q({"x":NaN}), allow_nan: true)["x"].object_id
70255410134280
70255410063100
70255410062620
也许我做错了什么?
答案 0 :(得分:2)
我认为这是一个深层实施细节。 Oj does this:
if (ni->nan) {
rnum = rb_float_new(0.0/0.0);
}
我无法找到相应的Ruby,Float.new
似乎不存在,但确实每个都创建一个新的Float
对象时间(来自实际C的现场构建的NaN),因此不同object_id
s。
而Ruby's JSON
module uses (also in C) its own JSON::NaN
Float
object everywhere:
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
这解释了为什么你会得到不同的NaN
s' object_id
与Oj相同,与Ruby的JSON相同。
无论生成的哈希值是object_id
,问题都出在NaN
上。如果它们具有相同的object_id
s,则封闭的哈希值被认为是相等的。如果没有,他们就不是。
根据文档,当{且仅当参数相同的对象时,Hash#==
使用Object#==
仅输出true
的值(同一{{} 1}})。这与NaN不等于自身的属性相矛盾。
壮观。继承已经过去了。
可能会修改Oj的C代码(甚至用它做一个拉取请求)来使用像Ruby的JSON模块那样的常量。这是一个微妙的变化,但我认为这是object_id
的精神。