3

有时在处理 API 响应时,我最终会编写如下内容:

what_i_need = response["key"]["another key"]["another key 2"]

"another key"这样做的问题是,如果缺少,它会抛出一个错误。我不喜欢那样。what_i_need如果过程中出现问题,我会更高兴nil

有没有比以下更优雅的解决方案:

what_i_need = nil
begin
  what_i_need = response["key"]["another key"]["another key 2"]
rescue Exception => e
end

我还考虑过猴子修补你尝试访问nil["something"]它的 NilClass 会返回nil,但我不确定这是否是最好的方法,如果可能的话。

4

4 回答 4

11

使用带有默认值的Hash#fetch 。

h = {:a => 2}
h.fetch(:b,"not present")
# => "not present"
h.fetch(:a,"not present")
# => 2

如果没有默认值,它将抛出KeyError.

h = {:a => 2}
h.fetch(:b)
# ~> -:2:in `fetch': key not found: :b (KeyError)

但是像你的嵌套Hash一样,你可以使用:

h = {:a => {:b => 3}}
val = h[:a][:b] rescue nil # => 3
val = h[:a][:c] rescue nil # => nil
val = h[:c][:b] rescue nil # => nil
于 2013-07-07T12:38:22.320 回答
6

Ruby 2.0 具有NilClass#to_h.

what_i_need = response["key"].to_h["another key"].to_h["another key 2"]
于 2013-07-07T12:58:20.060 回答
2

从 Objective-C 的键值编码系统中获得一些灵感,您可以使用轻量级 DSL 来遍历任意嵌套数据结构中的一系列键:

module KeyValue
  class << self
    def lookup(obj, *path)
      path.inject(obj, &:[]) rescue nil
    end
  end
end

h = { a: { b: { c: 42, d: [ 1, 2 ] } }, e: "test"}

KeyValue.lookup(h, :a, :b, :d, 1) # => 2
KeyValue.lookup(h, :a, :x)        # => nil

或者,如果您只想要单线:

(["key", "another key", "another key 2"].inject(h, &:[]) rescue nil)
于 2013-07-07T14:18:39.183 回答
1

要稍微扩展@Priti的答案Hash#fetch,您可以使用链而不是Hash#[]返回空哈希,直到到达链中的最后一个,然后返回nil

what_i_need = response.fetch('key', {})
                      .fetch('another key', {})
                      .fetch('another key 2', nil)

或依赖引发的 KeyError 异常(可能不是最好的,因为应避免作为控制流的异常):

what_i_need = begin
                response.fetch('key').fetch('another key').fetch('another key 2')
              rescue KeyError
                nil
              end
于 2013-07-07T14:09:32.223 回答