最美的解决方案是Mladen Jablanović的一篇旧答案,它允许您在散列中深入挖掘,而不像使用直接的.try()
调用那样限制深度,如果你想保持代码的美观:
class Hash
def get_deep(*fields)
fields.inject(self) {|acc,e| acc[e] if acc}
end
end
你应该小心处理各种对象(尤其是params
),因为字符串和数组也响应于 :[] 方法,但返回的值可能与你想要的不同,并且当字符串或符号用作索引时,数组会引发异常。
这就是为什么在下面的建议格式方法中使用了.is_a?(Hash)
的 (通常难看的) 测试而不是 (通常更好的) .respond_to?(:[])
的原因:
class Hash
def get_deep(*fields)
fields.inject(self) {|acc,e| acc[e] if acc.is_a?(Hash)}
end
end
a_hash = {:one => {:two => {:three => "asd"}, :arr => [1,2,3]}}
puts a_hash.get_deep(:one, :two ).inspect
puts a_hash.get_deep(:one, :two, :three ).inspect
puts a_hash.get_deep(:one, :two, :three, :four).inspect
puts a_hash.get_deep(:one, :arr ).inspect
puts a_hash.get_deep(:one, :arr, :too_deep ).inspect
如果没有使用这个丑陋的 "is_a?(Hash)" 作为保护,那么最后一个例子将会引发异常: "Symbol as array index (TypeError)"。
Hash#dig
方法,使得这里不再需要使用try
。现在 @baxang 给出的答案最好。 - user513951