39
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rubyの「ブロック」を理解する

Last updated at Posted at 2019-04-21

Rubyのブロックを雰囲気で使ってる人に向けて、ブロックの使い方を整理する。

ブロックとはなにか

ブロックは「処理の集合体」です。無名関数とかラムダ式とかクロージャのようなものです。

例:

# { ... } がブロック
[1,2,3,4].map { |e| e + 1 }

# do ... endがブロック
[1,2,3,4].map do |e|
  e + 1
end

ブロックは「メソッドに渡す」という形式でしか存在できません。なので、例えば以下のコードはSyntax Errorになります。

a = { |e| e + 1 }

当然、以下のコードもSyntax Errorです

a = do |e|
  e + 1
end

ブロック付きメソッド呼び出し

メソッドがブロックを受け取る方法を説明します。

yield

1つ目のやりかたは、yieldを使うことです。

例:

def hoge
  yield(100)
end

hoge { |e| e + 1 } # => 101

ちょっと分かりづらいですが、yieldがブロックを「起動」していると思ってください。yieldの引数がブロックの引数になります。

ちなみに、メソッドには ブロックとは別に 引数を渡すことができます。

def hoge(a)
  puts a
  yield(100)
end

hoge(1000) { |e| e + 1 } # => 101
# => "1000" が出力される

&block

2つ目のやりかたは、&block引数を使うことです。

def hoge(&block)
  block.call(100)
end

hoge { |e| e + 1 } # => 101

このように&blockという引数を宣言すると、ブロックがblock変数に代入されます。そして、block.callメソッドを呼ぶと、ブロックの処理が実行されます。直感的ですね。

この場合も、ブロックとは別に引数を渡すことができます。

def hoge(a, &block)
  block.call(a)
end

hoge(1000) { |e| e + 1 } # => 1001

Proc オブジェクト

「さっき『ブロックは変数に代入できない』って言ったじゃん!」と思った人がいると思います。
実はblockに入っているのはブロックではなく「Procオブジェクト」です。

Procオブジェクトは以下のように生成できます。

blk1 = Proc.new { |e| e + 1 }
blk1.call(100) # => 101

blk2 = proc { |e| e + 2 }
blk2.call(100) # => 102

Procはオブジェクトなので、変数に代入できます。
つまり、メソッドが&block変数でブロックを受けると、上のような処理が走ってブロックをオブジェクトにしているということですね。

Procからブロックへの変換

Procをブロックとしてメソッドに渡したい気持ちになることがあります。

plus_100 = proc { |e| e + 100 }
[1,2,3].map(plus_100) # => Error!

しかしこれはエラーになります。なぜならplus_100はProcオブジェクトであってブロックではないからです。

Procオブジェクトをブロックに変換するためには&を使います。

plus_100 = proc { |e| e + 100 }
[1,2,3].map(&plus_100) # => [101, 102, 103]

このように、&をProcオブジェクトの前につけることによって、Procオブジェクトを「展開」し、ブロックとしてメソッドに渡すことができます。

まとめ

  • ブロックとは処理の集合体である
  • ブロックは「メソッド呼び出しに渡す」という使い方しかできない
  • メソッドがブロックを受け取る方法は2つある
    • yield 命令
    • &block 引数
  • ブロックをオブジェクトに変換するとProcになる
    • block = Proc.new { |e| e + 1 }
    • block = proc { |e| e + 1 }
  • Procをブロックに変換するには&を使う
    • array.map(&block)
39
19
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?