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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 05:00:17  来源:igfitidea点击:

Ruby - Access multidimensional hash and avoid access nil object

rubyhashconditional

提问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

You could also use Object#andand.

您也可以使用Object#andand

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

回答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你可以看看这个, 也许