Ruby 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
我没有使用三重嵌套平面阵列。什么是一个如何有用的现实例子?
更新
事实证明,这些方法解决了一个最常见的Ruby问题。下面的问题有20个重复,所有这些都是使用dig
:
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
Ruby Style: How to check whether a nested hash element exists
答案 0 :(得分:58)
在我们的案例中,由NoMethodError
引用引起的nil
是迄今为止我们在生产环境中看到的最常见的错误。
新的Hash#dig
允许您在访问嵌套元素时省略nil
个检查。由于哈希最适合用于数据结构未知或易变的情况,因此对此有官方支持非常有意义。
让我们举个例子吧。以下内容:
user.dig(:user, :address, :street1)
不等同于:
user[:user][:address][:street1]
如果user[:user]
或user[:user][:address]
为nil
,则会导致运行时错误。
相反,它等同于以下,这是当前的习语:
user[:user] && user[:user][:address] && user[:user][:address][:street1]
注意将在别处创建的符号列表传递给Hash#dig
是多么微不足道,而从这样的列表中重新创建后一个构造并不是非常简单。 Hash#dig
可让您轻松进行动态访问,而无需担心nil
引用。
显然Hash#dig
也短得多。
需要注意的一点是,Hash#dig
本身会返回nil
,如果任何一个键变成了,这可能会导致同一类错误一步,所以提供合理的默认值是个好主意。 (这种提供始终响应预期方法的对象的方式称为Null Object Pattern。)
再次,在你的例子中,一个空字符串或类似“N / A”的东西,取决于有意义的东西:
user.dig(:user, :address, :street1) || ""
答案 1 :(得分:9)
一种方法是与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
答案 2 :(得分:0)
这对于通过深度嵌套的哈希/数组进行工作很有用,例如,这可能是您从API调用中得到的结果。
理论上,它可以节省大量代码,否则它们将在每个级别检查是否存在另一个级别,否则,您可能会不断出错。 实践上,您可能仍需要很多这样的代码,因为在某些情况下dig
仍会产生错误(例如,如果链中的任何内容都是非键对象)。
因此,您的问题实际上是真的有效-dig
尚未看到我们可能期望的用法。例如,在这里对此进行评论:Why nobody speaks about dig。
要使dig
避免这些错误,请尝试使用KeyDial的gem,我将其写成dig
,并在出现任何错误时强制使其返回nil / default。