📌
Ruby の #values_at と #fetch_values の違い
Hash と Array にそれぞれ #values_at と #fetch_values メソッドが定義されています。
この2つはそれぞれ『複数の要素に添字アクセスし、その値を配列で返す』ということをします。
Hash であればキーを Array であればインデックスを渡す感じですね。
# 複数のキーを渡して、その値を配列として返す
hash = { a: 1, b: 2, c: 3 }
pp hash.values_at(:a, :c) # => [1, 3]
pp hash.fetch_values(:a, :c) # => [1, 3]
# 配列の場合はインデックスを渡す
ary = %w(homu mami mado)
pp ary.values_at(0, 2) # => ["homu", "mado"]
pp ary.fetch_values(0, 2) # => ["homu", "mado"]
#values_at と #fetch_values の違い
#values_at は #[] と同じように『参照する要素が存在しない場合』は『 nil 』になります。
hash = { a: 1, b: 2, c: 3 }
pp hash.values_at(:a, :c, :x) # => [1, 3, nil]
ary = %w(homu mami mado)
pp ary.values_at(0, 2, 42) # => ["homu", "mado", nil]
一方で #fetch_values は『参照する要素が存在しない場合』は『例外』になります。
hash = { a: 1, b: 2, c: 3 }
hash.fetch_values(:a, :c, :x) rescue pp $!
# => #<KeyError: key not found: :x>
ary = %w(homu mami mado)
ary.fetch_values(0, 2, 42) rescue pp $!
# => #<IndexError: index 42 outside of array bounds: -3...3>
#[] ではなくて #fetch と同じように例外になる挙動ですね。
また #fetch と同じように『値が見つからなかった場合にブロック引数を呼び出す』という挙動になります。
hash = { a: 1, b: 2, c: 3 }
pp hash.fetch_values(:a, :c, :x) { "#{_1}はない" }
# => [1, 3, "xはない"]
# => #<KeyError: key not found: :x>
ary = %w(homu mami mado)
pp ary.fetch_values(0, 2, 42) { "#{_1}はない" }
# => ["homu", "mado", "42はない"]
参照する際に『 nil になってほしい』か『例外が発生し、意図的に中断してほしい』かで使い分けるとよさそうですね。
ちなみに Array#fetch_values は Ruby 3.4 から追加されています。
Discussion