为什么在使用变量访问从 JSON 解析的 Ruby 散列的元素时出现 NoMethodError?

Why do I get NoMethodError when using variables to access elements of a Ruby hash parsed from JSON?

我正在尝试使用使用 JSON gem 的 Ruby 脚本来解析示例 JSON 文件。这是我要解析的文件:

{
  "page": {
    "title": "Templating Example"
  },
  "teacher": {
    "name": "Mr. Bill"
  },
  "students": [
    { "name": "Bruce Wayne", "nicknames": ["Batman"] },
    { "name": "Peter Parker", "nicknames": ["Spidey", "Spiderman", "Spider-Man"] }
  ]
}

我可以使用以下脚本从 JSON 中提取数据:

require 'json'
file = File.read("data.json")
        response = JSON.parse(file)
        page_title = response["page"]["title"]

在上面的例子中,page_title returns "Templating Example"

我遇到麻烦的地方是当我试图将变量放入我的 "page" 和 "title" 位置时,类似于:

var1 = "page"
var2 = "title"
page_title = response["var1"]["var2"]

我尝试了各种解决方案,使用引号和不使用引号,转义引号,传递已经用括号和引号格式化的变量,但我总是得到一个错误:

undefined method `[]' for nil:NilClass (NoMethodError)

`undefined method `response' for main:Object (NoMethodError)

您似乎正尝试将 [] 与您的 JSON 中不存在的密钥(方法参数)一起使用。例如:

hash = { foo: 1, bar: 2 }
hash[:foo] #this key exists in hash
#=> 1
hash[:some_var] #this key not exists
#=> nil
hash[:some_var][:var2] #call [] method on nil class
#=>undefined method `[]' for nil:NilClass (NoMethodError)

如果您想在 response 散列中添加一个值,请这样写:

response[:var1] = {}
response[:var1][:var2] = your_value

或者:

response[:var1] = { var2: your_value } 

或者问题出在这里:

response["#{var1}"]["#{var2}"]

response[var1][var2]

应该是

var1 = "page"
var2 = "title"
page_title = response[var1][var2]

否则 var1 将被评估为内容为 var1 的字符串,而不是 "the content of the var1".

问题:缺少哈希键

page_title = response["var1"]["var2"]

这些键不是变量,它们是字符串。您引用的字符串键不存在于您发布的哈希中。使用您当前的代码,您需要:

{ 'var1' => {'var2' => :foo} }

存在于(或被合并到)你的散列中以使其工作。否则,如果 'var1' 键不存在,则无法在不引发 NoMethodError 异常的情况下对其调用 [] 方法。

您可以通过使用变量作为键来解决这个问题,或者通过下面描述的其他方式。

可能的解决方案

您有多种选择,具体取决于您真正想做什么:

  1. 在 Ruby 2.3.0 或更高版本中,使用 Hash#dig 以避免在尝试获取嵌套值时出现异常。例如:

    response.dig 'page', 'title'
    #=> "Templating Example"
    
    response.dig 'var1', 'var2'
    #=> nil
    

    如果 return 值为 nil,你显然仍然需要决定要做什么,但至少你不会得到意外的异常。

  2. 使用实际变量而不是字符串来表示您的哈希键。例如:

    var1 = 'page'
    var2 = 'title'
    
    response[var1][var2]
    #=> "Templating Example"
    
  3. 在执行您的操作之前,将另一个哈希合并到响应哈希(例如使用 Hash#merge!)。例如:

    var_hash = { 'var1' => {'var2' => :foo} }
    response.merge! var_hash
    response['var1']['var2']
    #=> :foo
    

这些解决方案中的任何一个或它们的组合都将帮助您解决问题。最适合您的方法取决于您的具体用例。