Ruby 在访问散列中的散列时,如何处理潜在错误?
有时,在处理API响应时,我会编写如下内容:Ruby 在访问散列中的散列时,如何处理潜在错误?,ruby,hash,Ruby,Hash,有时,在处理API响应时,我会编写如下内容: what_i_need = response["key"]["another key"]["another key 2"] 问题是,如果缺少另一个键,它将抛出一个错误。我不喜欢那样。如果我需要什么在过程中出现了nil,我会高兴得多 是否有比以下更优雅的解决方案: what_i_need = nil begin what_i_need = response["key"]["another key"]["another key 2"] rescue
what_i_need = response["key"]["another key"]["another key 2"]
问题是,如果缺少另一个键,它将抛出一个错误。我不喜欢那样。如果我需要什么
在过程中出现了nil
,我会高兴得多
是否有比以下更优雅的解决方案:
what_i_need = nil
begin
what_i_need = response["key"]["another key"]["another key 2"]
rescue Exception => e
end
我还考虑了monkey patching NilClass,如果您尝试访问nil[“something”]
,它将返回nil
,但我不确定这是否是最好的方法,如果可能的话。使用默认值
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)
但是使用嵌套的散列
,您可以使用:
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
Ruby 2.0拥有
NilClass\to\u h
what_i_need = response["key"].to_h["another key"].to_h["another key 2"]
要展开一点,可以使用的链而不是返回空哈希,直到到达链中的最后一个,然后返回nil
:
what_i_need = response.fetch('key', {})
.fetch('another key', {})
.fetch('another key 2', nil)
或者依赖于引发的KeyError异常(可能不是最好的,因为应该避免控制流异常):
从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
。如果您没有使用异常
e
,那么就没有必要编写=>e
。如果您使用的是rescue
,那么就没有特别的理由从Hash[]
切换到Hash#fetch
,这将使您的第二个解决方案与OPs相同。OK。我明白你的意思。你认为援救<代码> KeyError <代码>比拯救<代码>异常< /代码>好。但是,即使只是StandardError,也可能会发生大量其他异常,您可能不想挽救这些异常。@AndrewMarshall我很喜欢您的Hash#fetch
实现。这很酷。为什么在这种情况下,开始救援是件坏事?什么是使用being rescue的好地方?你可以把它写得更短:array.inject(h,&:[])rescue nil
@sawa在这种情况下,接收器将是路径中的元素,而不是散列?@naomik是的。这是一个很酷的功能。您可以对数组执行类似的操作,如array[0]。to_a[1]
。to_a
和to_h
名称的原因是什么?它们看起来不太合适。我希望像try\u a
或try\u h
这样的事情总会成功to_a
总是将某物转换为数组to_h
总是将某些内容转换为散列。哇,以前从未见过您的上一个示例。我总是有。到处试试。
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)