📌

Ruby の #values_at と #fetch_values の違い

に公開

HashArray にそれぞれ #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 から追加されています。

GitHubで編集を提案

Discussion