Ruby – 访问多维哈希,并避免访问零对象

可能重复:
Ruby:IF语句中的Nils
有没有一个干净的方法,以避免调用一个嵌套的params哈希零的方法?

比方说,我尝试访问这样的哈希:

my_hash['key1']['key2']['key3'] 

如果hash1中存在key1,key2和key3,那么这很好,但是如果key1不存在呢?

然后我会得到NoMethodError: undefined method [] for nil:NilClass 。 没有人喜欢这个

到目前为止,我处理这个做一个条件如:

if my_hash['key1'] && my_hash['key1']['key2']

这是否合适,有没有其他最坏的方式呢?

有很多方法来做到这一点。

如果你使用Ruby 2.3或更高版本,你可以使用dig

 my_hash.dig('key1', 'key2', 'key3') 

大量的人坚持平原ruby,连锁&&守卫testing。

你也可以使用stdlib Hash#获取 :

 my_hash.fetch('key1', {}).fetch('key2', {}).fetch('key3', nil) 

有些像链接ActiveSupport的#try方法。

 my_hash.try(:[], 'key1').try(:[], 'key2').try(:[], 'key3') 

其他人使用andand

 myhash['key1'].andand['key2'].andand['key3'] 

有些人认为以自我为中心的尼尔斯是一个好主意(虽然有人可能会追捕你,如果他们发现你这样做,就会折磨你)。

 class NilClass def method_missing(*args); nil; end end my_hash['key1']['key2']['key3'] 

您可以使用Enumerable#reduce (或别名注入)。

 ['key1','key2','key3'].reduce(my_hash) {|m,k| m && m[k] } 

或者也许用嵌套的查找方法扩展哈希或者只是你的目标哈希对象

 module NestedHashLookup def nest *keys keys.reduce(self) {|m,k| m && m[k] } end end my_hash.extend(NestedHashLookup) my_hash.nest 'key1', 'key2', 'key3' 

哦,我们怎么能忘记可能的 monad?

 Maybe.new(my_hash)['key1']['key2']['key3'] 

你也可以使用Objectandandand 。

 my_hash['key1'].andand['key2'].andand['key3'] 

条件my_hash['key1'] && my_hash['key1']['key2']不感觉干 。

备择scheme:

1) autovivification魔术。 从那个职位:

 def autovivifying_hash Hash.new {|ht,k| ht[k] = autovivifying_hash} end 

然后,用你的例子:

 my_hash = autovivifying_hash my_hash['key1']['key2']['key3'] 

它与Hash.fetch方法类似,都使用新的哈希值作为默认值,但是这会将细节移动到创build时间。 无可否认,这有点作弊:它永远不会返回“零”只是一个空的散列,它是在飞行中创build的。 根据你的使用情况,这可能是浪费。

2)用查找机制抽象出数据结构,处理幕后的未知情况。 一个简单的例子:

 def lookup(model, key, *rest) v = model[key] if rest.empty? v else v && lookup(v, *rest) end end ##### lookup(my_hash, 'key1', 'key2', 'key3') => nil or value 

3)如果你觉得单调,你可以看看这个, 也许