1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

RubyのブロックオブジェクトProcの詳細解説

2022-01-30 16:34:55

Proc オブジェクト

Procは、ブロックから変換されるオブジェクトである。Procを作成する方法は、以下の4つです。

コード例

# Method 1
inc = Proc.new { | x | x + 1}
inc.call(2) #=> 3

# method 2
inc = lambda {| x | x + 1 }
inc.call(2) #=> 3

# method 3
inc = ->(x) { x + 1}
inc.call(2) #=> 3

# method 4
inc = proc {|x| x + 1 }
inc.call(2) #=> 3



上記4つの他に、&演算子を使ってコードブロックをProcオブジェクトに変換する方法があります。コードブロックをメソッドのパラメータとして渡す必要がある場合、このパラメータに & 記法を追加することで行う必要があり、その位置はパラメータの最後である必要があります。

この&という記号は、次のような意味です。これはブロックとして使用したいProcオブジェクトです。この&記号を削除すると、再びProcオブジェクトが得られます。

コード例

def my_method(&the_proc)
  the_proc
end

p = my_method {|name| "Hello, #{name} !"}
p.class #=> Proc
p.call("Bill") #=> "Hello,Bill"


def my_method(greeting)
  "#{greeting}, #{yield}!"
end

my_proc = proc { "Bill" }
my_method("Hello", &my_proc)



留意点

ブロックを使うときは、裏方のワーカーと位置づけるprocの存在を無視します。私はよく、次のようなコードを書きます。

 def f(...)
  ...
  yield
  ...
 end

 def f(... , &p)
  ...
  p.call
  ...
 end

 def f(... , &p)
  instance_eval &p
  ...
 end

 def f(... , &p)
  ...
  defime_method m, &p
  ...
 end



初心者の中には、次のようなコードを書いて、実行時にエラーを報告する人がいます。

 def f(... , &p)
  instance_eval p
 end

 def f(... , p)
  instance_eval p.call
 end



また、このように書かれています。

 def f(... , &p)
  instance_eval do
   p.call
  end
 end


または

 def f(...)
  instance_eval do
   yield
  end
 end


というようなコードも書いたことがあります。

 def f(...)
  instance_eval yield
 end


ブロックをぶら下げるべきなのにprocオブジェクトを引数としてメソッドに渡してしまったり、&pがブロックでありメソッドに直接与えられることを理解していなかったり、ブロックとprocをきちんと区別せず、&pはブロック、pはproc、最終手段として明示的にprocを作らないという失敗をしたことがあります。ブロックとprocの関係に迷ったときは、数行読むだけでいいんです。