言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Ruby辞典

  1. トップページ
  2. Ruby辞典
  3. ブロック / yield / block_given?

ブロック / yield / block_given?

対応: Ruby 1.8(2003)

ブロックはメソッドに渡せる処理のかたまりです。『yield』でブロックを呼び出し、『block_given?』でブロックの有無を確認できます。

構文

# ブロック付きでメソッドを呼び出す(do...end 形式)
メソッド名 do |引数|
  処理
end

# ブロック付きでメソッドを呼び出す({} 形式)
メソッド名 { |引数| 処理 }

# メソッド定義内でブロックを呼び出す
def メソッド名
  yield         # ブロックを実行する
  yield(引数)   # 引数を渡してブロックを実行する
end

# ブロックが渡されているか確認する
def メソッド名
  if block_given?
    yield
  end
end

構文一覧

構文・メソッド概要
do...end複数行のブロックを定義します。優先順位が低いためメソッド引数との組み合わせで使われます。
{ }1行のブロックを定義します。優先順位が高く、インラインで書く際に使われます。
yieldメソッドに渡されたブロックを実行します。引数を渡すことができます。
block_given?メソッドにブロックが渡されているかどうかを真偽値で返します。

サンプルコード

『greet』は yield でブロックを呼び出すメソッドです。

block_yield.rb
def greet
  puts "開始します。"
  yield  # ブロックを実行する
  puts "終了しました。"
end

greet do
  puts "こんにちは!"
end

# yield で引数を渡す
def double(num)
  yield(num * 2)
end

double(5) { |n| puts "結果: #{n}" }  # 結果: 10

# block_given? でブロックの有無を確認する
def optional_process(val)
  if block_given?
    yield(val)
  else
    puts "ブロックなし: #{val}"
  end
end

optional_process(42)               # ブロックなし: 42
optional_process(42) { |n| puts "ブロックあり: #{n}" }  # ブロックあり: 42

# yield の戻り値を使う
def convert(text)
  result = yield(text)
  puts "変換後: #{result}"
end

convert("hello") { |s| s.upcase }  # 変換後: HELLO
ruby block_yield.rb
開始します。
こんにちは!
終了しました。
結果: 10
ブロックなし: 42
ブロックあり: 42
変換後: HELLO

Procオブジェクトでブロックを受け取る

proc_example.rb
# &proc でブロックを明示的にオブジェクトとして受け取る
def run_twice(&block)
  block.call
  block.call
end

run_twice { puts "未来ガジェット!" }
# 未来ガジェット!
# 未来ガジェット!

# Proc.new または lambda でブロック相当のオブジェクトを作成する
greet_proc = Proc.new { |name| puts "こんにちは、#{name}!" }
greet_proc.call("岡部倫太郎")  # こんにちは、岡部倫太郎!

# & でProcをブロックとして渡す
names = ["岡部倫太郎", "牧瀬紅莉栖", "椎名まゆり"]
names.each(&greet_proc)
# こんにちは、岡部倫太郎!
# こんにちは、牧瀬紅莉栖!
# こんにちは、椎名まゆり!
ruby proc_example.rb
未来ガジェット!
未来ガジェット!
こんにちは、岡部倫太郎!
こんにちは、岡部倫太郎!
こんにちは、牧瀬紅莉栖!
こんにちは、椎名まゆり!

よくあるミス1: block_given?未確認のyield

『block_given?』を確認せずに『yield』を呼ぶと、ブロックなしで呼ばれた場合に LocalJumpError が発生します。

block_mistake.rb
def risky_method
  yield
end

risky_method
ruby block_mistake.rb
block_mistake.rb:2:in 'Object#risky_method': no block given (yield) (LocalJumpError)
	from block_mistake.rb:5:in '<main>'

よくあるミス2: block_given?で安全に処理

『block_given?』で確認すれば安全です。

block_ok.rb
def safe_method
  if block_given?
    yield
  else
    puts "ブロックが渡されていません"
  end
end

safe_method
safe_method { puts "安全!" }
ruby block_ok.rb
ブロックが渡されていません
安全!

よくあるミス3: do...endと{ }の優先順位

『do...end』と『{ }』は優先順位が異なるため、メソッドの引数と組み合わせると意図と異なる動作になります。メソッド引数との組み合わせでは『{ }』を使うと安全です。

block_map.rb
result = [1, 2, 3].map { |n| n * 2 }
puts result.inspect
ruby block_map.rb
[2, 4, 6]

概要

ブロックはRubyの重要な機能で、メソッドに処理を後付けするための仕組みです。『each』や『map』などのイテレータもブロックを受け取るメソッドとして実装されています。

『do...end』と『{ }』はどちらもブロックを定義しますが、慣習として複数行は『do...end』、1行は『{ }』を使います。ブロックなしで『yield』を呼び出すと『LocalJumpError』が発生するため、ブロックが任意の場合は必ず『block_given?』で確認してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。