如何使用 Ruby 2.3 中引入的 Array#dig 和 Hash#dig?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34346653/
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
How do I use Array#dig and Hash#dig introduced in Ruby 2.3?
提问by user513951
Ruby 2.3 introduces a new method on Arrayand Hashcalled dig. The examples I've seen in blog posts about the new release are contrived and convoluted:
红宝石2.3引入了一个新的方法Array和Hash所谓的dig。我在有关新版本的博客文章中看到的示例是人为的和令人费解的:
# Hash#dig
user = {
user: {
address: {
street1: '123 Main street'
}
}
}
user.dig(:user, :address, :street1) # => '123 Main street'
# Array#dig
results = [[[1, 2, 3]]]
results.dig(0, 0, 0) # => 1
I'm not using triple-nested flat arrays. What's a realistic example of how this would be useful?
我没有使用三重嵌套平面阵列。这将如何有用的一个现实例子是什么?
UPDATE
更新
It turns out these methods solve one of the most commonly-asked Ruby questions. The questions below have something like 20 duplicates, all of which are solved by using dig:
事实证明,这些方法解决了最常见的 Ruby 问题之一。下面的问题大约有 20 个重复项,所有这些问题都可以通过使用来解决dig:
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
如何避免嵌套散列中缺少元素的 NoMethodError,而无需重复 nil 检查?
Ruby Style: How to check whether a nested hash element exists
回答by Drenmi
In our case, NoMethodErrors due to nilreferences are by far the most common errors we see in our production environments.
在我们的例子中,NoMethodErrors 由于nil引用是迄今为止我们在生产环境中看到的最常见的错误。
The new Hash#digallows you to omit nilchecks when accessing nested elements. Since hashes are best used for when the structure of the data is unknown, or volatile, having official support for this makes a lot of sense.
新Hash#dig功能允许您nil在访问嵌套元素时省略检查。由于哈希最适合用于数据结构未知或易变的情况,因此获得官方支持非常有意义。
Let's take your example. The following:
让我们以你的例子为例。下列:
user.dig(:user, :address, :street1)
Is notequivalent to:
是不是等同于:
user[:user][:address][:street1]
In the case where user[:user]or user[:user][:address]is nil, this will result in a runtime error.
在 whereuser[:user]或user[:user][:address]is的情况下nil,这将导致运行时错误。
Rather, it is equivalent to the following, which is the current idiom:
相反,它等效于以下,这是当前的习语:
user[:user] && user[:user][:address] && user[:user][:address][:street1]
Note how it is trivial to pass a list of symbols that was created elsewhere into Hash#dig, whereas it is not very straightforward to recreate the latter construct from such a list. Hash#digallows you to easily do dynamic access without having to worry about nilreferences.
请注意,将在别处创建的符号列表传递到 中是多么微不足道Hash#dig,而从这样的列表中重新创建后一个构造并不是很简单。Hash#dig允许您轻松进行动态访问,而不必担心nil引用。
Clearly Hash#digis also a lot shorter.
显然Hash#dig也短了很多。
One important point to take note of is that Hash#digitself returns nilif any of the keys turn out to be, which can lead to the same class of errors one step down the line, so it can be a good idea to provide a sensible default. (This way of providing an object which always responds to the methods expected is called the Null Object Pattern.)
需要注意的一个重要点是,如果任何键被证明是,Hash#dig它本身就会返回nil,这可能会导致同一类错误,因此提供一个合理的默认值可能是一个好主意。(这种提供始终响应预期方法的对象的方式称为空对象模式。)
Again, in your example, an empty string or something like "N/A", depending on what makes sense:
同样,在你的例子中,一个空字符串或类似“N/A”的东西,取决于什么是有意义的:
user.dig(:user, :address, :street1) || ""
回答by acsmith
One way would be in conjunction with the splat operator reading from some unknown document model.
一种方法是与 splat 操作员一起阅读一些未知的文档模型。
some_json = JSON.parse( '{"people": {"me": 6, ... } ...}' )
# => "{"people" => {"me" => 6, ... }, ... }
a_bunch_of_args = response.data[:query]
# => ["people", "me"]
some_json.dig(*a_bunch_of_args)
# => 6
回答by Convincible
It's useful for working your way through deeply nested Hashes/Arrays, which might be what you'd get back from an API call, for instance.
它对于处理深度嵌套的哈希/数组很有用,例如,这可能是您从 API 调用中得到的。
In theoryit saves a ton of code that would otherwise check at each level whether another level exists, without which you risk constant errors. In practiseyou still may need a lot of this code as digwill still create errors in some cases (e.g. if anything in the chain is a non-keyed object.)
从理论上讲,它节省了大量代码,否则会在每个级别检查另一个级别是否存在,否则您将面临不断出错的风险。在实践中,您可能仍然需要大量此代码,因为dig在某些情况下仍会产生错误(例如,如果链中的任何内容是非键对象。)
It is for this reason that your question is actually really valid - dighasn't seen the usage we might expect. This is commented on here for instance: Why nobody speaks about dig.
正是出于这个原因,您的问题实际上确实有效 -dig没有看到我们可能期望的用法。例如,这里对此进行了评论:为什么没有人谈论 dig。
To make digavoid these errors, try the KeyDialgem, which I wrote to wrap around digand force it to return nil/default if any error crops up.
为了dig避免这些错误,请尝试使用KeyDialgem,我编写dig它来环绕并强制它在出现任何错误时返回 nil/default。

