Help us understand the problem. What is going on with this article?

[Ruby]Procオブジェクトについて

More than 1 year has passed since last update.

Rubyの「Procオブジェクト」について学んだことをまとめてみました。本記事よりもより正確かつ詳細な内容が必要な場合は、巻末に記載の参考文献やリファレンスマニュアルなどをご参照ください。

Procオブジェクトとは

Procオブジェクトとはブロックをオブジェクト化したProcクラスのインスタンスです。

Procオブジェクトの作り方

Procオブジェクトの作り方は複数あります。

# 作り方その1 (Proc.new)
proc_sample1 = Proc.new "ブロック"

# 作り方その2 (procメソッド)
proc_sample2 = proc "ブロック"

# 作り方その3 ("->")
proc_sample3 = ->"引数のリスト" "引数を使って実行する処理の内容"

# 作り方その4 (lambdaメソッド)
proc_sample4 = lambda "ブロック"

Procオブジェクトの使い方

Procオブジェクトを実行

Procオブジェクトはブロックのオブジェクトなので、そのままでは実行されません。Procオブジェクトを実行する方法は複数あります。

# Procオブジェクトを生成
add_proc = ->(a, b) { a + b }

# 実行方法その1 (callメソッド)
add_proc.call(1, 2)  #=> 3

# 実行方法その2 (yieldメソッド)
add_proc.yield(1, 2)  #=> 3

# 実行方法その3 (".()")
add_proc.(1, 2)  #=> 3

# 実行方法その4 ("[]")
add_proc[1, 2]  #=> 3

Procオブジェクトをブロックの代わりとして渡す

引数にブロックを受け取るメソッドに対して、ブロックの代わりにProcオブジェクトを渡すことができます。

# 引数にブロックを受け取るメソッドを定義
def greeting(&block)
  puts 'おはよう'
  text = block.call('こんにちは')
  puts text
  puts 'こんばんは'
end

# Procオブジェクトを生成
shout_proc = ->(text) { text + '!' * 3 }

# Procオブジェクトをブロックの代わりに渡す
greeting(&shout_proc)
#=> おはよう
#   こんにちは!!!
#   こんばんは

Procオブジェクトを普通の引数として渡す

Procオブジェクトを普通の引数としてメソッドに渡すこともできます。

# 普通の引数を受け取るメソッドを定義
def greeting(arrange_proc)
  puts 'おはよう'
  text = arrange_proc.call('こんにちは')
  puts text
  puts 'こんばんは'
end

# Procオブジェクトを生成
shout_proc = Proc.new { |text| text + '!' * 3 }

# Procオブジェクトを普通の引数として渡す
greeting(shout_proc)
#=> おはよう
#   こんにちは!!!
#   こんばんは

Proc.newとlambdaの違い

Procオブジェクトの作り方その1およびその2で生成したProcオブジェクト(ここでは"Proc.new"と呼びます)と、その3およびその4で生成したProcオブジェクト(ここでは"lambda"と呼びます)は、挙動が少し異なります。

違いその1 〜引数の扱い〜

lambdaはProc.newよりも引数のチェックが厳密です。

# Proc.newは 「想定している引数の数」 と 「実際に渡された引数の数」 が不一致でも動作する
add_proc = Proc.new { |a, b| a.to_i + b.to_i }
add_proc.call(1)  #=> 1 (不足している引数は nil として扱われる)
add_proc.call(1, 3, 5)  #=> 4 (3つ目の引数は無視される)

# lambdaは 「想定している引数の数」 と 「実際に渡された引数の数」 が不一致の場合はエラーとなる
add_proc = ->(a, b) { a.to_i + b.to_i }
add_proc.call(1)  #=> ArgumentError: wrong number of arguments (given 1, expected 2)
add_proc.call(1, 3, 5)  #=> ArgumentError: wrong number of arguments (given 3, expected 2)

違いその2 〜return/breakの挙動〜

Proc.newやlambdaの中でreturn/breakを使った場合、以下のような挙動の違いがあります。

return break
Proc.new メソッドを抜ける 例外が発生する
lambda lambda内の処理から抜ける   lambda内の処理から抜ける  

厳密にはもう少し違いはあるのですが、詳しく知りたい方は以下を参照ください。
returnやbreakを使ったときのProc.newとラムダの挙動の違い
Ruby リファレンスマニュアル

上記挙動の違いはややこしいので、Proc.newやlambdaの中ではできるだけreturn/breakを使わないようにするのが賢明のようです。

参考文献

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした