为什么在使用变量访问从 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 异常的情况下对其调用 []
方法。
您可以通过使用变量作为键来解决这个问题,或者通过下面描述的其他方式。
可能的解决方案
您有多种选择,具体取决于您真正想做什么:
在 Ruby 2.3.0 或更高版本中,使用 Hash#dig 以避免在尝试获取嵌套值时出现异常。例如:
response.dig 'page', 'title'
#=> "Templating Example"
response.dig 'var1', 'var2'
#=> nil
如果 return 值为 nil,你显然仍然需要决定要做什么,但至少你不会得到意外的异常。
使用实际变量而不是字符串来表示您的哈希键。例如:
var1 = 'page'
var2 = 'title'
response[var1][var2]
#=> "Templating Example"
在执行您的操作之前,将另一个哈希合并到响应哈希(例如使用 Hash#merge!)。例如:
var_hash = { 'var1' => {'var2' => :foo} }
response.merge! var_hash
response['var1']['var2']
#=> :foo
这些解决方案中的任何一个或它们的组合都将帮助您解决问题。最适合您的方法取决于您的具体用例。
我正在尝试使用使用 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 异常的情况下对其调用 []
方法。
您可以通过使用变量作为键来解决这个问题,或者通过下面描述的其他方式。
可能的解决方案
您有多种选择,具体取决于您真正想做什么:
在 Ruby 2.3.0 或更高版本中,使用 Hash#dig 以避免在尝试获取嵌套值时出现异常。例如:
response.dig 'page', 'title' #=> "Templating Example" response.dig 'var1', 'var2' #=> nil
如果 return 值为 nil,你显然仍然需要决定要做什么,但至少你不会得到意外的异常。
使用实际变量而不是字符串来表示您的哈希键。例如:
var1 = 'page' var2 = 'title' response[var1][var2] #=> "Templating Example"
在执行您的操作之前,将另一个哈希合并到响应哈希(例如使用 Hash#merge!)。例如:
var_hash = { 'var1' => {'var2' => :foo} } response.merge! var_hash response['var1']['var2'] #=> :foo
这些解决方案中的任何一个或它们的组合都将帮助您解决问题。最适合您的方法取决于您的具体用例。