プログラミング備忘録

プログラミングの学習状況をメモしています

51日目

今日の学習

Ruby

久々にRuby本の学習。今日は、「第10章 yieldとProcを理解する」の部分を読む。

yieldといえば、Railsapplication.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にブロックを渡せばよい。

詳しくはまた次回。