Ruby - 访问多维哈希并避免访问 nil 对象
Posted
技术标签:
【中文标题】Ruby - 访问多维哈希并避免访问 nil 对象【英文标题】:Ruby - Access multidimensional hash and avoid access nil object [duplicate] 【发布时间】:2012-04-25 05:18:30 【问题描述】:可能重复:Ruby: Nils in an IF statementIs there a clean way to avoid calling a method on nil in a nested params hash?
假设我尝试访问这样的哈希:
my_hash['key1']['key2']['key3']
如果 key1、key2 和 key3 存在于散列中,这很好,但如果 key1 不存在怎么办?
然后我会得到NoMethodError: undefined method [] for nil:NilClass
。没有人喜欢这样。
到目前为止,我通过以下条件处理这个问题:
if my_hash['key1'] && my_hash['key1']['key2']
...
这样合适吗,还有其他 Rubiest 方法吗?
【问题讨论】:
接受的答案提到了所有可能的方法,除了 Ruby 2.3+ 的正确方法:ruby-doc.org/core-2.3.1/Hash.html#method-i-dig 【参考方案1】:有很多方法可以解决这个问题。
如果你使用 Ruby 2.3 或以上版本,可以使用dig
my_hash.dig('key1', 'key2', 'key3')
很多人坚持使用纯红宝石并链接&&
守卫测试。
您也可以使用 stdlib Hash#fetch:
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']
有些人认为egocentric nils 是个好主意(尽管有人发现你这样做可能会追捕你并折磨你)。
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]
或者也许使用嵌套查找方法扩展 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'
哦,我们怎么能忘记 maybe monad?
Maybe.new(my_hash)['key1']['key2']['key3']
【讨论】:
你也可以试试 monadic gem,它有一个 Maybe(和其他 monads)来帮助处理异常 您对在声明末尾使用rescue nil
有何想法?
@jakeonrails rescue nil
几乎总是邪恶的。 1)它可以捕获并静默丢弃您不知道可能会引发的异常; 2) 异常是计算成本高的流控制——应该只将它们用于异常行为,而不是预期行为。
Ruby 2.3之后可以使用dig
方法进行哈希,ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig
我之前的评论中安全导航运算符的哈希值语法不正确。正确的语法是:my_hash&.[]('key1')&.[]('key2')&.[]('key3')
.【参考方案2】:
您也可以使用Object#andand。
my_hash['key1'].andand['key2'].andand['key3']
【讨论】:
【参考方案3】:条件my_hash['key1'] && my_hash['key1']['key2']
感觉不到DRY。
替代方案:
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 方法类似,都使用新的哈希值作为默认值,但这会将细节转移到创建时间。 诚然,这有点作弊:它永远不会返回 'nil' 只是一个空散列,它是动态创建的。根据您的用例,这可能是一种浪费。
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) 如果你觉得单子,你可以看看这个,Maybe
【讨论】:
以上是关于Ruby - 访问多维哈希并避免访问 nil 对象的主要内容,如果未能解决你的问题,请参考以下文章