Procオブジェクトはブロックをオブジェクト化するために使用します。
分かりにくいと思うので例を交えながら説明していきます。
Procオブジェクトの宣言方法
以下のように「new」でインスタンス化します。
[192] pry(main)> proc = Proc.new { puts 'foo'}
=> #<Proc:0x00007fdced9cfc58@(pry):310>
[193] pry(main)> proc.class
=> Proc
[194] pry(main)> proc.call
foo
proc内でproc外の変数を参照することもできます。
以下のようにproc内で変数fooを参照しています。callメソッドで呼び出すとfoo変数で参照されている「foo」が表示されます。
その後、foo変数に「bar」を代入し、再度callメソッドを呼び出すと「bar」が表示され、proc外の変数も同じものを見ていることが分かります。
[195] pry(main)> foo = :foo
=> :foo
[196] pry(main)> proc = Proc.new { puts foo}
=> #<Proc:0x00007fdcee1003d8@(pry):314>
[197] pry(main)> proc.call
foo
=> nil
[198] pry(main)> foo = :bar
=> :bar
[200] pry(main)> proc.call
bar
=> nil
proc内で未定義の変数を参照する
Proc内で未定義の変数を参照すると以下のようにエラーになります。
[201] pry(main)> proc = Proc.new { puts hoge }
=> #<Proc:0x00007fdcee198818@(pry):319>
[202] pry(main)> proc.call
NameError: undefined local variable or method `hoge' for main:Object
from (pry):319:in `block in __pry__'
また、procをインスタンス化した後に、hoge変数に値を代入しても同様にエラーになってしまいます。
そのためprocでproc外の変数を参照するためには、procオブジェクト作成前に変数を定義しておく必要があります。
[201] pry(main)> proc = Proc.new { puts hoge }
=> #<Proc:0x00007fdcee198818@(pry):319>
[202] pry(main)> proc.call
NameError: undefined local variable or method `hoge' for main:Object
from (pry):319:in `block in __pry__'
[203] pry(main)> hoge = :hoge
=> :hoge
[204] pry(main)> proc.call
NameError: undefined local variable or method `hoge' for main:Object
from (pry):319:in `block in __pry__'
yieldメソッド
以下の例を見てください。
yieldメソッドは引数としてブロックを渡すことができます。
以下の例では仮引数を省略する形で記載されています。
コードの説明をすると、test_yieldというメソッドを作成し、その中でyieldメソッドを呼び出しており、引数には二つの数値を渡してします。
一番最後の行でtest_yieldに引数でブロックを渡して呼び出しています。
このブロックではa,bという変数が定義され、「a + b」の結果を返す処理が記載されています。
特定の処理(この場合a + b)をブロックとして、引数に渡し、メソッド内でそのブロックを実行できるということです。
def test_yield
yield(1, 2)
end
puts test_yield { |a, b| a + b }
#結果
-> 3
今度は引数を明示的に記載する例を見てみましょう。
以下のように「&」をつけた仮引数を定義することでブロックで渡された引数をprocオブジェクトで受け取ることができます。
ブロックを受け取る変数は仮引数の一番最後に記載される必要があります。
def test_yield(&proc)
yield(1, 2)
end
puts test_yield { |a, b| a + b }
以下ではyieldメソッドではなくcallメソッドで実行しています。結果は同じになります。
def test_yield(&proc)
proc.call(1, 2)
end
puts test_yield { |a, b| a + b }
#結果
-> 3
ブロックが渡されたかどうかの確認を以下のようにして実行できます。
def test_yield
if block_given?
yield
else
puts 'NOT given block'
end
end
test_yield { 'given block' }
#結果
->"given block"
test_yield
#結果
->NOT given block
コメント