如何使用对象作为json的键将红宝石哈希/结构序列化/反序列化

时间:2018-09-14 14:00:27

标签: json ruby hashmap

我想将Ruby中的嵌套数据结构转储到json(我知道Marshal模块,但我需要标准格式),并且能够再次加载/解析该数据结构。捕获:我将结构(或更简单的示例:哈希)用作哈希键。示例:

require 'json'
h = {{hello: 123} => 123}
JSON.parse(JSON.generate(h)) #=> {"{:hello=>123}"=>123}

问题是,JSON.generate(h)将键{:hello => 123}序列化为字符串,当我再次解析结果时,它仍然是字符串。

如何解决此问题并在生成/解析后重新获得原始结构?

1 个答案:

答案 0 :(得分:3)

JSON仅允许将字符串用作对象键。因此,所有键都调用 to_s

您将有以下选择来解决您的问题:

  1. 最好的选择是更改数据结构,以便可以将其正确序列化为JSON。

  2. 您必须亲自处理该字符串化密钥。当哈希转换为可以使用Kernel#eval之类的字符串Andrey Deineko suggested in the comments进行转换时,散列会产生完全有效的Ruby语法。

    result = json.transform_keys { |key| eval(key) }
           # json.transform_keys(&method(:eval)) is the same as the above.
    

    Hash#transform_keys方法是相对较新的(从Ruby 2.5.0开始可用),当前可能不在您的开发环境中。您可以根据需要用简单的Enumerable#map替换它。

    result = json.map { |k, v| [eval(k), v] }.to_h
    

    注意::如果传入的JSON包含我强烈建议的任何用户生成的内容,则不要使用 eval ,因为您可能允许用户在服务器上执行代码。