Ruby - 访问多维散列并避免访问 nil 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10130726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby - Access multidimensional hash and avoid access nil object
提问by Nobita
Possible Duplicate:
Ruby: Nils in an IF statement
Is there a clean way to avoid calling a method on nil in a nested params hash?
可能的重复:
Ruby:IF 语句中的 Nils
是否有一种干净的方法可以避免在嵌套的 params 哈希中调用 nil 上的方法?
Let's say I try to access a hash like this:
假设我尝试访问这样的哈希:
my_hash['key1']['key2']['key3']
This is nice if key1, key2 and key3 exist in the hash(es), but what if, for example key1 doesn't exist?
如果 key1、key2 和 key3 存在于散列中,这很好,但是如果例如 key1 不存在呢?
Then I would get NoMethodError: undefined method [] for nil:NilClass. And nobody likes that.
然后我会得到NoMethodError: undefined method [] for nil:NilClass. 没有人喜欢那样。
So far I deal with this doing a conditional like:
到目前为止,我处理这个做一个条件,如:
if my_hash['key1'] && my_hash['key1']['key2']...
if my_hash['key1'] && my_hash['key1']['key2']...
Is this appropriate, is there any other Rubiest way of doing so?
这是否合适,是否还有其他 Rubyest 方法可以这样做?
回答by dbenhur
There are many approaches to this.
对此有很多方法。
If you use Ruby 2.3 or above, you can use dig
如果您使用 Ruby 2.3 或更高版本,则可以使用dig
my_hash.dig('key1', 'key2', 'key3')
Plenty of folks stick to plain ruby and chain the &&guard tests.
很多人坚持使用普通的 ruby 并链接&&防护测试。
You could use stdlib Hash#fetchtoo:
你也可以使用 stdlib Hash#fetch:
my_hash.fetch('key1', {}).fetch('key2', {}).fetch('key3', nil)
Some like chaining ActiveSupport's #trymethod.
有些人喜欢链接 ActiveSupport 的#try方法。
my_hash.try(:[], 'key1').try(:[], 'key2').try(:[], 'key3')
Others use andand
其他人使用andand
myhash['key1'].andand['key2'].andand['key3']
Some people think egocentric nilsare a good idea (though someone might hunt you down and torture you if they found you do this).
有些人认为以自我为中心的 nil是个好主意(尽管如果有人发现你这样做,他们可能会追捕你并折磨你)。
class NilClass
def method_missing(*args); nil; end
end
my_hash['key1']['key2']['key3']
You could use Enumerable#reduce(or alias inject).
您可以使用Enumerable#reduce(或别名注入)。
['key1','key2','key3'].reduce(my_hash) {|m,k| m && m[k] }
Or perhaps extend Hash or just your target hash object with a nested lookup method
或者可能使用嵌套查找方法扩展 Hash 或只是您的目标哈希对象
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'
Oh, and how could we forget the maybemonad?
哦,我们怎么可能忘了,也许单子?
Maybe.new(my_hash)['key1']['key2']['key3']
回答by Sergio Tulentsev
回答by inger
Conditions my_hash['key1'] && my_hash['key1']['key2']don't feel DRY.
条件my_hash['key1'] && my_hash['key1']['key2']不觉得干燥。
Alternatives:
备择方案:
1) autovivificationmagic. From that post:
1)自动复活魔法。从那个帖子:
def autovivifying_hash
Hash.new {|ht,k| ht[k] = autovivifying_hash}
end
Then, with your example:
然后,以您的示例:
my_hash = autovivifying_hash
my_hash['key1']['key2']['key3']
It's similar to the Hash.fetch approach in that both operate with new hashes as default values, but this moves details to the creation time. Admittedly, this is a bit of cheating: it will never return 'nil' just an empty hash, which is created on the fly. Depending on your use case, this could be wasteful.
它类似于 Hash.fetch 方法,因为两者都以新的哈希值作为默认值进行操作,但这会将细节转移到创建时间。诚然,这有点作弊:它永远不会返回 'nil' 只是一个空的散列,它是动态创建的。根据您的用例,这可能很浪费。
2) Abstract away the data structure with its lookup mechanism, and handle the non-found case behind the scenes. A simplistic example:
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) If you feel monadic you can take a look at this, Maybe
3)如果你觉得monadic你可以看看这个, 也许

