おさとの雑記帳

日々の学習のアウトプットに使っていきます!

Rubyでよく見る(&:)を読み解く

目次

はじめに

この記事はCODE BASE OKINAWA Advent Calendar 2022 - Adventarの10日目のエントリーです。
今まで何気なく使っていた(&:method)がどういう挙動をしているのか見ていきます。
↓こんなやつ

%w(urasoe naha ginowan).map(&:upcase)
#=> ["URASOE", "NAHA", "GINOWAN"]

前知識

(&:)を理解するために必要な知識をそれぞれ見ていきます。

Proc

Procとはブロックをオブジェクトにしたものです。
例えば↓のような使い方ができます。

square = Proc.new { |x| x ** 2 }

square.call(3)

#=> 9

&修飾

Procオブジェクトをブロックとして渡す場合には引数の前に&が必要です。

square = Proc.new { |x| x ** 2 }
[1, 2, 3, 4, 5].map(&square) # Procオブジェクトを渡しているので`:`はつかない
#=> [1, 4, 9, 16, 25]

また、メソッドをブロックとして渡す場合は一度to_procでProcオブジェクトに変換する必要があります。

class Integer
  define_method :square do
    self ** 2
  end
end

square = :square.to_proc # ①

[1, 2, 3, 4, 5].map(&square)
#=> [1, 4, 9, 16, 25]

(&:method)を解読する

前知識を踏まえていよいよ(&:)を解読してみます。

例のコードを読んでみる

例に挙げたコードをもう一度貼っておきます。

%w(urasoe naha ginowan).map(&:upcase)
=> ["URASOE", "NAHA", "GINOWAN"]
  1. &に:upcaseが渡されます
  2. &修飾に:methodを渡すと①で見たProcオブジェクトへの変換が行われます。つまり、シンボルのメソッドに対しto_procが呼び出されます
  3. :upcaseが変換されたProcオブジェクトとなります
  4. 3で変換されたProcオブジェクトがブロックとしてmapに渡されます
  5. その後Procの節で見たように、Procオブジェクトとなったupcase.call()引数に配列の各要素を受け取ります
  6. mapメソッドはProcオブジェクトを実行した戻り値を新たな配列に追加します

上記のような流れを経て(&:method)は動いているのですね。

まとめ

メタプログラミングRubyやチェリー本を読んで面白かったので自分なりに(&:method)について整理してみました。
よきRubyライフを💎

参考