🍣

[Rails][Ruby] (&:メソッド名)とは。 Procと:メソッドのコンビネーションでブロックを簡潔に

2 min read 2

&:メソッドとは

&:メソッド&:メソッドの組み合わせでできた熟語のようなもので、ブロックを伴うメソッドを簡潔書く記法です。

&はいろんな意味がありますが、ここでは、Procクラスのxxx(&b)という使われ方です。

:メソッド名はシンボルにしています。シンボルにしているのは、:を付けないと変数名になってしまうからです。

簡単に言うと、対象のメソッドの引数に対して、:が付いたメソッドが使われるブロックのまとまりとして、ブロック{}の代わりに渡すことです。

使用例

# &とシンボルを使ってブロックを簡潔に書く
['ruby', 'java', 'perl'].map { |s| s.upcase } # => ["RUBY", "JAVA", "PERL"]
# ↓書き換え
['ruby', 'java', 'perl'].map(&:upcase) # => ["RUBY", "JAVA", "PERL"]

上記の例では、mapメソッドにブロック{}を渡す代わりに&:メソッド名という引数を渡しています。

この書き方は以下の条件が揃ったときにだけ使えます。

  1. ブロックの引数が1個だけである(s)
  2. ブロックの中で呼び出すメソッドには引数がない(upcase)
  3. ブロックの中では、ブロック引数に対してメソッドを一回呼び出す以外の処理が無い(s.upcaseだけ)

変換できない例

# ブロックの中でメソッドではなく演算子を使っている
p [1, 2, 3, 4, 5, 6].select { |n| n % 5 == 0 }

# ブロックの中で使うメソッドに引数を渡している
p [1, 10, 11, 12].map { |n| n.to_s(2) }

# ブロックの中でメソッドを複数実行している
[1, 2, 3, 4].map do |n| 
  m = n * 5
  m.to_s
end

てかProcてなに

Procとは、簡単に言うとブロックをオブジェクト化するものです。

例)

proc = Proc.new { |n| n * 2 }
proc.class
# => Proc

つまり、Procインスタンスはブロックのようなものです。

Procで使う&は、メソッドが引数としてブロック渡したり、受け取ったりできるようにするために付けます。

def greeting(&block)
  puts '寿司'
  text = block.call('めちゃ')
  puts text
  puts '食べたい'
end

repeat_proc = Proc.new { |text| text * 2 }
greeting(&repeat_proc)
# => 寿司
#    めちゃめちゃ
#    食べたい

このとき、&はProcインスタンスをブロックとして、受け渡しできるようにするだけでなく、to_procメソッドも実行しています。

to_procメソッドが実行されるとそのオブジェクトはProcオブジェクトとなります。

ただ、上記のように元からProcクラスから生成されたProcオブジェクトに対してto_procを実行しても自分自身が返るだけです。

もうひとつ、Procオブジェクト以外にto_procが使えるのが今回の&:メソッド名で使われていた:シンボルです。

そのため、シンボルの付いたメソッドに対して、&によってtp_procが実行されてProcオブジェクト(ブロック)に変換されていました。

[1, 2, 3].map(&:to_s)
# => ["1", "2", "3"]
  1. &が付くとそのシンボル(メソッド)はto_procメソッドが実行され、Procオブジェクトとなります。
  2. Procはブロックをオブジェクト化するクラスなので、ブロック化したto_sメソッドとなります。
  3. 対象のメソッド(map)に引数として渡します。
  4. 対象のメソッドから受け取った各配列要素を第一引数としてto_sブロックで実行します。
  5. よって、["1", "2", "3"]が返り値となります。

つまり、Procインスタンスではないオブジェクトに対して&が付くと:メソッドに対してto_procを呼び出してProcオブジェクト化します。

参考

伊藤 淳一 「プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ)」, 技術評論社, 2017/11/25

Rubyで使われる記号の意味(正規表現の複雑な記号は除く)

&演算子と、procと、Object#method について理解しなおす - Qiita

【Ruby】array.map(&:method)を理解する - Qiita

Railsでよくみる arr.map(&:to_s)の意味を教えてください|teratail

Discussion

yusuke_docha さん、こんにちは。
こちらの記事ですが、全体的に拙著「プロを目指す人のためのRuby入門」のサンプルコードや本文を踏襲しているように思います。
もし本書を参考にしているのであれば、参考文献を明記してもらえるとありがたいです。
よろしくお願いします。

Junichi Ito様、こんにちは。
日々、書籍・Qiita記事等参考にさせて頂いております。
大変申し訳ありませんでした。当記事に参考文献として明記させて頂きました。

ログインするとコメントできます