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入門サイトおすすめ3選!初心者向けの学習方法を解説

2017年10月24日

 

The following two tabs change content below.

Tomoyuki

SEを5年経験後、全くの未経験ながら思い切ってブロガーに転身し、月間13万PVを達成。その後コロナの影響も受け、以前から興味があったWeb系エンジニアへのキャリアチェンジを決意。現在はWeb系エンジニアとして働きながら、プロゲーマーとしても活躍できるように活動中。








シェアはこちらから


【2024年】おすすめのゲーミングPC

モンハンワイルズの発売日とPC版(Steam版)の推薦スペックが公開されたので、おすすめのゲーミングPCをご紹介!


コメントを残す

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