【Ruby】Procオブジェクト

javascriptRubyでいうところのProcのような書き方が多いんだよね〜」と村田講師から教えていただいたが、そもそもProcがわからないので今回はrubyのProcオブジェクトを学習していきます。

 

前提知識

procを学習する前に、いくつか頭に入れておかないといけない前提知識があるみたいで。

  • Rubyの関数(メソッド)は直接変数に代入したり、他の関数に渡す事ができない。
  • Rubyの関数(メソッド)を変数に代入したり、他の関数に渡すためには、関数をObject#methodでラップする必要がある。・・・①
  • Object#methodでラップしたメソッドを実行させるためには、Object#callを実行させる必要がある。・・・②
  • ②を別の関数に引き渡すこともできる。・・・③
def square(n)
  n * n
end

sq = method(:square)・・・①

sq.call(3) # => 9・・・②

def print_func(arg, fun)・・・③
  puts fun.call(arg)
end

print_func(4, sq)

# >> 16

無邪気な少年A: 関数Aを関数Bに渡したいです!

Rubyさん: じゃあこの2つの手続きを踏むといいよ

  1. 関数Aをmethodで囲む。
  2. 1で加工した関数Aを関数Bの引数に入れ、関数の中身でcallする

ブロック

do...endや{}で囲まれた塊のこと。

def print_func(arg, &fun)
  puts fun.call(arg)
end

#do..endで書いた場合
print_func(4) do |n|
n * n
end
# >> 16

#ブロックで書いた場合
print_func(4) { |n| n * n }

# >> 16

yield

ブロックの説明で書いていた& + call を yieldで表現できるようになる。

def print_func(arg)
  puts yield(arg)
end

#do..endで書いた場合

print_func(4) do |n|
n * n
end
# >> 16

#ブロックで書いた場合

print_func(4) { |n| n * n }

# >> 16

Procとは

ブロックをコンテキスト(ローカル変数のスコープやスタックフレーム)とともにオブジェクト化した手続きオブジェクト

何ができる?

ブロックを他の関数に渡す事ができるらしい。

ブロックをProcオブジェクトにするにはlambdaprocProc.new->の何れかを使う。

lambda { **|**n**|** n ***** n } *# => #<Proc:0x007f89a1852960@-:13 (lambda)>*

proc { **|**n**|** n ***** n } *# => #<Proc:0x007f89a18526b8@-:14>*

Proc.**new** { **|**n**|** n ***** n } *# => #<Proc:0x007f89a1852438@-:15>*

**->**n{ n ***** n } *# => #<Proc:0x007f89a1852190@-:16 (lambda)>*

それぞれが下記のような特徴を持つ

							return                     next                     break
Proc.new    メソッドを抜ける            手続きオブジェクトを抜ける  例外が発生する
proc        メソッドを抜ける            手続きオブジェクトを抜ける  例外が発生する
lambda      手続きオブジェクトを抜ける   手続きオブジェクトを抜ける  手続きオブジェクトを抜ける
イテレータ   メソッドを抜ける            手続きオブジェクトを抜ける  メソッドを抜ける

以下のような感じでyieldと組み合わせてブロックを渡すもしくは代入する事ができる。

square = ->n{ n * n }・・・"->"でprocしている。

square.call(3) # => 9 ・・・callでprocを実行させる事ができる

def print_func(arg,fun)
  puts fun.call(arg)
end

print_func(4, square) 

# >> 16

procオブジェクトはそれ自体に名前がないため、無名関数と呼ばれる。

def print_func(arg, fun)
  puts fun.call(arg)
end

print_func(4,->n{ n* n })

# >> 16

まとめ

  • procオブジェクトはブロックを他の関数に渡すための無名関数
  • 関数を変数に入れて実行する場合や、他の関数に渡す場合は、Object#methodでラップし、Object#callで実行させればいい。

一言

ざっくりとしかprocを知れてなかったけど、今回procを学習したおかげでこれからはrailsにスッキリとしたコードが書けるような気がしてきた!

Procを制する者がRubyを制す(嘘)