Rubyのメソッドでブロックを使う方法


こんにちは。Tomoyuki(@tomoyuki65)です。

Rubyではブロックが使えますよね。

基本的にはRuby標準のメソッドでブロックを使いますが、自分で作成したメソッドでもブロックが使えるんです。

この記事では、Rubyのブロックについて解説します。

 



ブロックとは?

ブロックとは、メソッドの引数として渡すことができる処理のかたまりです。

例えば、以下のようなプログラムのdo〜endを指します。

num = [10, 20, 30]
sum = 0
num.each do |n|
  sum += n
end

 

尚、do〜endは { } で置き換えることもできます。

num = [10, 20, 30]
sum = 0
num.each { |n|
  sum += n
}

 

メソッドでブロックを使う方法

自分で作成したメソッドでもブロックを使うことができます。

例えば、メソッドからブロックの処理を呼び出す場合は、以下のように「yield」を使います。

def test_block
puts "Start"
yield
puts "End"
end
test_block do
puts "ブロックを渡す"
end

 

実行結果
Start
ブロックを渡す
End

 

実行結果の通り、メソッドの「yield」にブロックが渡され、ブロックの処理が行われます。

 

メソッドからブロックに引数を渡す

メソッドからブロックに引数を渡すこともできます。

例えばブロックに引数を渡したい場合は、以下のように書きます。

def test_block
puts "Start"
yield "メソッドから引数を渡す"
puts "End"
end
test_block do |text|
puts text
end

 

実行結果
Start
メソッドから引数を渡す
End

 

ブロックがメソッドに渡されたかを確認

ブロックがメソッドに渡されたかを確認することもできます。

その場合は「block_given?」メソッドを使用します。

def test_block
puts "Start"
# ブロックが渡された場合のみ実行する
if block_given?
yield
end
puts "End"
end
# ブロックなしで実行
test_block
# ブロックありで実行
test_block do
puts "ブロックを渡す"
end

 

実行結果
Start
end
Start
ブロックを渡す
End

 

ブロックを引数として明示的に受け取る

ブロックをメソッドの引数として明示的に受け取ることもできます。

ブロックを引数として受け取る場合は、引数名の前に「&」を付け、ブロックを実行する場合はcallメソッドを使います。

def test_block(&block)
puts "Start"
# callメソッドでブロックを実行
block.call
puts "End"
end
test_block do
puts "ブロックを渡す"
end

 

実行結果
Start
ブロックを渡す
End

 

このように、Ruby標準のメソッドだけでなく、自分で作ったメソッドにもブロックを使うことができます。

 



Procクラスによるブロックのオブジェクト

Procクラスを使用すると、ブロックをオブジェクト化することができます。

Procオブジェクトを実行する場合は、callメソッドを使います。

例として、以下のプログラムを実行してみて下さい。

block_proc = Proc.new do
puts "Procオブジェクト"
end
block_proc.call

 

実行結果
Procオブジェクト

 

また、実行時に引数を利用することもできます。

block_proc = Proc.new do |text|
puts "Procオブジェクト + #{text}"
end
block_proc.call('引数を利用')

 

実行結果
Procオブジェクト + 引数を利用

 

Procオブジェクトをメソッドの引数に渡す

Procオブジェクトは、メソッドの引数として渡すことができます。

先ほどの「ブロックを引数として明示的に受け取る」で確認したプログラムのブロックを、Procオブジェクトに変更しても渡すことができます。

def test_block(&block)
puts "Start"
# callメソッドでブロックを実行
block.call
puts "End"
end
block_proc = Proc.new { puts "ブロックを渡す" }
test_block(&block_proc)

 

実行結果
Start
ブロックを渡す
End

 

また、Procオブジェクトは、普通の引数としても渡すことができます。

普通の引数として渡す場合は、「&」を付けないことに注意して下さい。

def test_block(block)
puts "Start"
# callメソッドでブロックを実行
block.call
puts "End"
end
block_proc = Proc.new { puts "ブロックを渡す" }
test_block(block_proc)

 

実行結果
Start
ブロックを渡す
End

 

ブロックとして渡す場合と普通の引数として渡す場合の違いとして、メソッドが受け取れるブロックの数は1つですが、普通の引数であれば制限はありません。

 

Procオブジェクトを作るもう一つの方法

Procオブジェクトは、「->」(ラムダリテラル)または「lambda」メソッドを使っても作ることができます。

def test_block(block)
puts "Start"
# callメソッドでブロックを実行
block.call
puts "End"
end
block_proc = -> { puts "ブロックを渡す" }
test_block(block_proc)

 

実行結果
Start
ブロックを渡す
End

 



Procとラムダの違い

Procとラムダはほぼ同じものですが、以下のような違いがあります。

  •  ラムダは引数のチェックが厳密
  •  returnとbreakを使った場合の挙動が異なる

 

ラムダは引数のチェックが厳密

ブロックに引数を渡す場合、ラムダは引数に過不足があるとエラーになります。

# Procの場合
block_proc = Proc.new { |text| puts text }
block_proc.call("a","b")
# ラムダの場合はエラー
block_rambda = ->(text) { puts text }
block_rambda.call("a", "b")

 

実行結果
Main.rb:13:in `block in ‘: wrong number of arguments (given 2, expected 1) (ArgumentError)
from Main.rb:14:in `’

 

returnとbreakを使った場合の挙動が異なる

Procやラムダの内部でreturnやbreakを使った場合に挙動が異なります。

returnの場合、Procではメソッドを抜けますがラムダはメソッドを抜けません。

# Procの場合
def proc
puts "proc_start"
block_proc = Proc.new { |text| return puts text }
block_proc.call([1, 2, 3])
puts "proc_end"
end
# ラムダの場合
def rambda
puts "rambda_start"
block_rambda = ->(text) { return puts text }
block_rambda.call([1, 2, 3])
puts "rambda_end"
end
# procメソッドを実行
proc
# rambdaメソッドを実行
rambda

 

実行結果
proc_start
1
2
3
rambda_start
1
2
3
rambda_end

 

またbreakの場合は、Procではエラーになりますがラムダはエラーになりません。

# Procの場合
def proc
puts "proc_start"
block_proc = Proc.new { |text| break puts text }
block_proc.call([1, 2, 3])
puts "proc_end"
end
# ラムダの場合
def rambda
puts "rambda_start"
block_rambda = ->(text) { break puts text }
block_rambda.call([1, 2, 3])
puts "rambda_end"
end
# procメソッドを実行(エラーとなる)
proc
# rambdaメソッドを実行
rambda

 

実行結果
Main.rb:4:in `block in proc’: break from proc-closure (LocalJumpError)
from Main.rb:5:in `proc’
from Main.rb:19:in `’

 

このように、メソッドでブロックを使う場合は色々な書き方があるため、それぞれの仕様を理解した上で使いわけれると良さそうです。

 

まとめ

  •  ブロックはメソッドの引数として渡すことができる処理のかたまり
  •  メソッドからブロックの処理を呼び出す場合は「yield」を使う
  •  「yield」の後に引数を書くと、ブロックに引数を渡すことができる
  •  ブロックがメソッドに渡されたかを確認するには「block_given?」メソッドを使う
  •  ブロックを引数として受け取る場合、引数名の前に「&」を付け、ブロックを実行する場合はcallメソッドを使う
  •  Procクラスを使用すると、ブロックをオブジェクト化することができる
  •  Procオブジェクトをメソッドの引数に渡すことができ、ブロックとして渡す場合は引数の前に「&」を付ける(メソッドには一つのブロックしか渡せない)
  •  Procオブジェクトは、普通の変数としてメソッドの引数に渡すこともできる
  •  Procオブジェクトは、「->」(ラムダリテラル)または「lambda」メソッドを使っても作成できる
  •  Procとラムダの違いは、ラムダは引数に厳密なことと、Procやラムダの内部でreturnやbreakを使った場合に挙動が異ること
  •  ブロックに引数を渡す場合、ラムダは引数に過不足があるとエラーになる
  •  returnの場合、Procではメソッドを抜けるがラムダはメソッドを抜けない
  •  breakの場合は、Procではエラーになるがラムダはエラーにならない

 

  • 関連記事

オススメのRuby入門サイトはどれ?Rubyの学習方法をまとめる

2017.10.24

 

The following two tabs change content below.
Tomoyuki

Tomoyuki

2018年1月1日に開業したプロブロガー1年目です。 元EBSエンジニア(SE)で、今はブログ運営とゲーム配信をしています。 Rubyを中心としたWeb開発情報や仮想通貨について情報発信中です!








シェアありがとうございます、


時代の変化とともに、多様な生き方へ

仕事がAIや自動化で無くなっていく時代を生き抜くために、
モノ創りと多様な生き方を示します。



ビットコインを買うならZaif取引所がおすすめ!

Zaif取引所は他の主要取引所と比べて手数料が安いのが特徴。
ビットコインの他、イーサリアム、モナーコイン、ネムも購入可能です。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です