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)如果你觉得单调,你可以看看这个, 也许