【问题标题】:Deep copy JSON object in RubyRuby 中的深拷贝 JSON 对象
【发布时间】:2013-09-09 23:55:37
【问题描述】:

我想在 Ruby 中深度复制一个 json 对象。但是,当我调用 clone json 对象时,它似乎并没有进行深层复制。有可能还是我做错了什么。这是我现在正在做的代码的相关sn-p:

idFile = File.new(options[:idFile])
idFile.each_line do |id|
    jsonObj = getJson(id)
    copyObj = jsonObj.clone
    copyObj['details']['payload'] = Base64.decode64(copyObj['payload'])
    copyObj['key'] = 1
    jsonObj['details']['payload'] = Base64.decode64(jsonObj['payload'])
    jsonObj['key'] = 2
    send(copyObj)
    send(jsonObj)  #error here
end

def getJson(id)
    idData = getData(id)
    idJson = JSON.parse!(idData)
    idJson = idJson['request'][0]
    return idJson
end

我的错误是由于解码调用而发生的。第一次解码调用已经解码了对象,第二次尝试再次解码相同的数据,在第二次发送调用中出错,因为此时数据是乱码。
如何深度复制该 json 对象?

【问题讨论】:

    标签: ruby ruby-1.9


    【解决方案1】:

    JSON 只是文本 - 在这种情况下,假定对象可以通过 JSON 序列化往返。

    因此最简单的方法是去Object->JSON(Text)->Object 获得真正的深度克隆;或者,反序列化 JSON 两次(一次用于深​​度克隆,因为两个反序列化在依赖对象图中产生)。请注意,这里的 Object 不是 JSON,而仅仅是作为标准 Ruby 对象的数据的反序列化表示(例如哈希和数组)。

    # Standard "deep clone" idiom using an intermediate serialization.
    # This is using JSON here but it is the same with other techniques that walk
    # the object graph (such as Marshal) and generate an intermediate serialization
    # that can be restored later.
    jsonObj = getJson(id)
    jsonObj["foo"] = "change something"
    json = JSON.generate(jsonObj)
    copyObj = JSON.parse(json)
    
    # Or, assuming simple deep clone of original, just deserialize twice.
    # (Although in real code you'd only want to get the JSON text once.)
    jsonObj = getJson(id)
    copyObj = getJson(id)
    

    如前所述,clone 没有做这个序列化/反序列化步骤,而只是归于shallow Object#clone semantics(实际上没有Hash#clone,所以它直接使用Object#clone 的实现) ):

    生成 obj 的浅拷贝——拷贝 obj 的实例变量,但不拷贝它们引用的对象..

    【讨论】:

    • 对不起,我不明白。 getJson(id) 调用执行 JSON.parse!(txt)。那不应该返回一个红宝石对象。文档说“将 JSON 文档源解析为 Ruby 数据结构并返回它。”那时它已经是一个哈希对象,我取了一个子哈希对象并尝试克隆它。根据文档,Ruby 哈希支持克隆。如果我打印出类,它会输出 Hash。
    • 确实返回一个 ruby​​ 对象。这就是为什么在第一个示例中,我们首先将其序列化回 JSON (json = JSON.generate ..),然后再对其进行反序列化。请注意,哈希支持克隆,但不支持深度克隆#clone 绝不应该是深度克隆!)。我提出的解决方案使用 Obj->JSON->Obj 进行克隆。另一种选择是使用 Marshall,例如 shown here。请注意,这两种方法都首先生成 intermediate 文档。 JSON,或者 Marshall 使用的。当然这也可以递归完成。
    • 我理解那部分。根据你的建议,我做了 JSON.parse(jsonObj.to_json)... 修复了我遇到的错误,但这似乎很乱。关于在 ruby​​-1.9 中深度复制 Hash 对象,我有什么遗漏吗?谷歌搜索都说 jsonObj.clone 应该深拷贝它。虽然我猜它的名字不正确,应该被称为 hashObj 这个问题......
    • @Niru 然后找到的资源不正确或引用了扩展名(例如deep_dup)或其他不同的环境。 Ruby 1.9.3 中有is no Hash#clone,所以它遵循浅语义的 Object#clone。
    • 啊抱歉....谷歌搜索结果无论如何都提到做马歇尔......所以看来我必须这样做。感谢大家的帮助!
    【解决方案2】:

    如果您只是想对任意 Ruby 对象进行深度复制,请尝试 deep_dive。

    https://rubygems.org/gems/deep_dive

    【讨论】:

      猜你喜欢
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 2012-06-19
      • 2019-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多