如何避免访问嵌套哈希的空元素时出现NoMethodError?

9

如果我尝试访问不存在的哈希元素,会出现 NoMethodError: undefined method '[]' for nil:NilClass 错误。但是,我无法预测哪些元素会存在。

@param_info = {}
@param_info["drug"]["name"]
# => NoMethodError: undefined method `[]' for nil:NilClass

当元素意外地为 nil 时,我该如何避免引发此错误?

4个回答

14
Ruby 2.3.0引入了一个名为dig的方法,可用于HashArray。如果在任何嵌套级别缺少元素,则返回nil
h1 = {}
h2 = { a: {} }
h3 = { a: { b: 100 } }

h1.dig(:a, :b) # => nil
h2.dig(:a, :b) # => nil
h3.dig(:a, :b) # => 100

您的使用情况将如下所示:

@param_info.dig('drug', 'name')

7
如果我理解你的问题正确,即在属性值丢失的情况下使其具有容错性,则可以尝试以下方法:
@param_info.try(:fetch, :drug).try(:fetch, :name)

这可能会返回nil,但这将消除错误undefined methods '[]' for nil:NilClass 更新:
为了处理不存在的键,你可以尝试以下方法。(从Equivalent of try for a hash中获得提示):
@param_info.try(:[], :drug).try(:[], :name)

我真的很喜欢这个简单易懂,但是它仍然给了我一个错误:找不到键值"drddsug"(我输入了随机字符进行测试)。 - Rob
@Rob,请查看我的更新答案。这将更加容错! - vee
1
@Rob Ruby 2.3.0 引入了一个叫做 Hash#dig 的新方法来解决这个问题。请看下面的答案。 - user513951

1
我会这样做:

我会像这样做:

begin
  @param_info.fetch(:drug).fetch(:name)
rescue KeyError
  # handle key not found
end

你可以在一个函数中完成它:
def param_info_key(info, key1, key2)
  info.fetch(key1).fetch(key2)
rescue KeyError
  nil
end

param_info_key({}, :a, :b) # nil
param_info_key({a: {}}, :a, :b) # nil
param_info_key({a: {b: "foo"}}, :a, :b) # "foo"

示例:

irb(main):001:0> s = {}
=> {}
irb(main):002:0> begin
irb(main):003:1*   s.fetch(:foo).fetch(:bar)
irb(main):004:1> rescue KeyError
irb(main):005:1>   puts "Key not found"
irb(main):006:1> end
Key not found
=> nil

0

你可以简单地使用 unless 来测试这个:

irb(main):001:0> def checker(val)
irb(main):002:1>   unless val.nil?
irb(main):003:2>     puts 'working on the railroad'
irb(main):004:2>     end
irb(main):005:1>   end
=> nil
irb(main):006:0> x = nil
=> nil
irb(main):007:0> checker(x)
=> nil
irb(main):008:0> y = 1
=> 1
irb(main):009:0> checker(y)
working on the railroad
=> nil
irb(main):010:0> 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接