红宝石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
我不使用三层嵌套的平阵列。什么的怎样,这将是有用的一个现实的例子吗?
UPDATE
事实证明,这些方法解决最常问的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
在我们的例子,NoMethodError
s由于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) || ""
一种方法是与图示操作者从一些不知名的文档模型一起阅读。
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
这是通过深度嵌套的散列/阵列,这可能是你会得到什么从API回电,例如工作的方式非常有用。
从理论上讲,可以节省一吨的代码,否则将层层把关另一个层面是否存在,否则,你的风险不断错误。在实践中,你可能仍然需要大量的代码作为dig
仍然会在某些情况下,创建错误(例如,如果链中的任何一个不带键的对象。)
正是出于这个原因,你的问题其实是真的有效 - dig
还没有看到我们所期望的使用。这是在这里评论例如:Why nobody speaks about dig。
为了使dig
避免这些错误,请尝试KeyDial宝石,这是我写的环绕dig
并迫使它,如果任何错误影响了返回零/默认。