如何一次获取多个散列值?

什么是这个短的版本?

from = hash.fetch(:from) to = hash.fetch(:to) name = hash.fetch(:name) # etc 

请注意,如果密钥不存在,我想提出一个错误。

必须有更短的版本,如:

 from, to, name = hash.fetch(:from, :to, :name) # <-- imaginary won't work 

如果需要,可以使用ActiveSupport。

使用哈希的values_at方法:

 from, to, name = hash.values_at(:from, :to, :name) 

这将返回nil的哈希中不存在的任何键。

Ruby 2.3最后引入了用于哈希的fetch_values方法,直接实现了这一点:

 {a: 1, b: 2}.fetch_values(:a, :b) # => [1, 2] {a: 1, b: 2}.fetch_values(:a, :c) # => KeyError: key not found: :c 
 hash = {from: :foo, to: :bar, name: :buz} [:from, :to, :name].map{|sym| hash.fetch(sym)} # => [:foo, :bar, :buz] [:frog, :to, :name].map{|sym| hash.fetch(sym)} # => KeyError 
 my_array = {from: 'Jamaica', to: 'St. Martin'}.values_at(:from, :to, :name) my_array.keys.any? {|key| element.nil?} && raise || my_array 

这会引起你要求的错误

  my_array = {from: 'Jamaica', to: 'St. Martin', name: 'George'}.values_at(:from, :to, :name) my_array.keys.any? {|key| element.nil?} && raise || my_array 

这将返回数组。

但OP要求失败的关键…

 class MissingKeyError < StandardError end my_hash = {from: 'Jamaica', to: 'St. Martin', name: 'George'} my_array = my_hash.values_at(:from, :to, :name) my_hash.keys.to_a == [:from, :to, :name] or raise MissingKeyError my_hash = {from: 'Jamaica', to: 'St. Martin'} my_array = my_hash.values_at(:from, :to, :name) my_hash.keys.to_a == [:from, :to, :name] or raise MissingKeyError 

您可以使用KeyError对象的默认值初始化您的散列。 这将返回一个KeyError的实例,如果你试图获取的密钥不存在。 所有你需要做的是检查它的(值)类,并提高它,如果它的KeyError。

 hash = Hash.new(KeyError.new("key not found")) 

让我们添加一些数据到这个散列

 hash[:a], hash[:b], hash[:c] = "Foo", "Bar", nil 

最后看看这些值,如果没有find密钥就会报错

 hash.values_at(:a,:b,:c,:d).each {|v| raise v if v.class == KeyError} 

当且仅当密钥不存在时,这将引发exception。 如果你有一个nil值的键,它不会抱怨。

最简单的事情我会去的

 from, to, name = [:from, :to, :name].map {|key| hash.fetch(key)} 

另外,如果你想使用values_at ,你可以使用一个带默认值块的Hash

 hash=Hash.new {|h, k| raise KeyError.new("key not found: #{k.inspect}") } # ... populate hash from, to, name = hash.values_at(:from, :to, :name) # raises KeyError on missing key 

或者,如果你这么喜欢,猴子补丁Hash

 class ::Hash def fetch_all(*args) args.map {|key| fetch(key)} end end from, to, name = hash.fetch_all :from, :to, :name