如何使用 Ruby 2.3 中引入的 Array#dig 和 Hash#dig?
How do I use Array#dig and Hash#dig introduced in Ruby 2.3?
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
一种方法是结合 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
在我们的例子中,由于 nil
引用导致的 NoMethodError
是迄今为止我们在生产环境中看到的最常见错误。
新的 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
本身 returns nil
如果任何键结果是,这可能导致相同的 class 的错误,所以提供一个合理的默认值是个好主意。 (这种提供始终响应预期方法的对象的方式称为 Null Object Pattern。)
同样,在您的示例中,空字符串或类似 "N/A" 的内容,具体取决于什么有意义:
user.dig(:user, :address, :street1) || ""
它对于处理深度嵌套的 Hashes/Arrays 非常有用,例如,这可能是您从 API 调用中得到的结果。
理论上它节省了大量代码,否则会在每个级别检查是否存在另一个级别,否则您将面临不断出错的风险。 在实践中你可能仍然需要很多这样的代码,因为dig
在某些情况下仍然会产生错误(例如,如果链中的任何东西是非键控对象。)
正是出于这个原因,您的问题实际上是有效的 - dig
没有看到我们可能期望的用法。例如,这里对此进行了评论:Why nobody speaks about dig.
为了让 dig
避免这些错误,请尝试 KeyDial gem,我写它来包围 dig
并强制它成为 return nil/default 如果出现任何错误。
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
一种方法是结合 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
在我们的例子中,由于 nil
引用导致的 NoMethodError
是迄今为止我们在生产环境中看到的最常见错误。
新的 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
本身 returns nil
如果任何键结果是,这可能导致相同的 class 的错误,所以提供一个合理的默认值是个好主意。 (这种提供始终响应预期方法的对象的方式称为 Null Object Pattern。)
同样,在您的示例中,空字符串或类似 "N/A" 的内容,具体取决于什么有意义:
user.dig(:user, :address, :street1) || ""
它对于处理深度嵌套的 Hashes/Arrays 非常有用,例如,这可能是您从 API 调用中得到的结果。
理论上它节省了大量代码,否则会在每个级别检查是否存在另一个级别,否则您将面临不断出错的风险。 在实践中你可能仍然需要很多这样的代码,因为dig
在某些情况下仍然会产生错误(例如,如果链中的任何东西是非键控对象。)
正是出于这个原因,您的问题实际上是有效的 - dig
没有看到我们可能期望的用法。例如,这里对此进行了评论:Why nobody speaks about dig.
为了让 dig
避免这些错误,请尝试 KeyDial gem,我写它来包围 dig
并强制它成为 return nil/default 如果出现任何错误。