51日目
今日の学習
Ruby
久々にRuby本の学習。今日は、「第10章 yieldとProcを理解する」の部分を読む。
yieldといえば、Railsのapplication.html.erb
に利用されていて、とにかくどこかから何かを参照できるという漠然としたイメージがある。
また、Railsチュートリアルではページタイトルをページごとにつける際にyieldを用いていた。
Procに関しては初耳なので、しっかり学習したい。
イントロダクションには「この章ではブロックを利用するメソッドの定義や、ブロックの処理を引数や変数として渡す方法を説明」と書かれている。
yield
ブロックの処理を呼び出す
yield
を使って、ブロックの処理を呼び出すことができる。
def greeting puts "おはよう" puts "こんばんは" end # ブロックをつけてみる greeting do puts "こんにちは" end #=>おはよう #=>こんにちは
greeting
メソッドを呼び出す時、puts "こんにちは"
というブロックをつけて実行すると、エラーが起きたりするわけではないが、何も変化がない。
ブロックの内容を実行するためには、メソッド内でyield
を使う。
挨拶の順番が時系列になるように、「おはよう」と「こんばんは」の間にyield
を挟んでみる。
def greeting puts "おはよう # ブロックの処理を呼び出す yield puts "こんばんは" end greeting do puts "こんにちは" end #=>おはよう #=>こんにちは #=>こんばんは
間に、ブロックで渡したputs "こんにちは"
が実行されている。
yield
は記述した分だけ繰り返しブロックの処理が行われるため、例えば2行続けてyield
を書けば、二回分ブロックの処理が行われる。
また、メソッド内でyield
を用いているにも関わらず、ブロックをつけずにメソッドを呼び出すとエラーが発生する。
# 実際のエラー内容 yield.rb:3:in `greeting': no block given (yield) (LocalJumpError)
ブロックの有無を確認してからyield
を呼び出す方法があり、block_given?
メソッドを利用する。ブロックが渡された場合はtrueになるため、ブロックがあればyield
を呼び出し、そうでない場合はそれ以外のメソッド部分を実行してくれる。
if block_given? yield end
上の例ではブロックの戻り値を受け取っていたが、逆にブロックに引数を渡したりすることもできる。
Ruby本では、引数をブロックに渡して、さらにブロックの戻り値を受け取りその内容をputsで出力するコード例が紹介されていた。
def greeting # ブロックに引数を渡して、戻り値を受け取る text = yield "こんにちは" # ブロックの戻り値を出力 puts text end greeting |text| # yieldで渡された文字列に、文字列を追加してみる text + '長谷川さん' end #=>こんにちは長谷川さん
ブロックを引数として明示的に受け取る
ブロックを引数として受け取る場合は、引数名の前に&
を使う。
そのブロックを実行する場合は、call
メソッドを使う。
# 引数名は自由につけてOK def メソッド(&引数) 引数.call end
また、ブロックが渡されたかどうかは、その引数がnil
かどうかで判断できる。nil?
を利用して、ブロックの有無に関わらずエラーなしで呼び出せるようにする。
# 引数名をblockに設定 def greeting(&block) # ブロックが渡されていなければnil unless block.nil? # callメソッドでブロックを実行 text = block.call('こんにちは') puts text end puts "こんばんは" end greeting do |text| text * 2 end #=> こんにちはこんにちは greeting #=> こんばんは
ブロックを引数にするメリットの1つは、ブロックを他のメソッドに引き渡せるようになること。
他のメソッドにブロックを引き渡す場合は、引数の手前にも&
をつける。
2つ目のメリットは、渡されたブロックに対してメソッドを呼び出して、必要な情報を取得したり、ブロックに対する何かしらの操作を実行したりできるようになること。
Ruby本で紹介されていた例は、arity
メソッドを使うとブロック引数の個数を確認することができて、引数の数に応じてif文で実行結果を変えるサンプルコードが載っていた。
もう一つの学習項目であるProc
クラスは、ブロックをオブジェクト化するためのクラス。
Proc
クラスからインスタンス(オブジェクト)を生成するには、Proc.new
にブロックを渡せばよい。
詳しくはまた次回。