30
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

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を使わないようにするのが賢明のようです。

参考文献

30
26
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?