1. genya0407

    Posted

    genya0407
Changes in title
+Rubyの「ブロック」を理解する
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,111 @@
+Rubyのブロックを雰囲気で使ってる人に向けて、ブロックの使い方を整理する。
+
+## ブロックとはなにか
+
+ブロックは「処理の集合体」です。無名関数とかラムダ式とかクロージャのようなものです。
+
+例:
+
+```ruby
+# { ... } がブロック
+[1,2,3,4].map { |e| e + 1 }
+
+# do ... endがブロック
+[1,2,3,4].map do |e|
+ e + 1
+end
+```
+
+**ブロックは「メソッドに渡す」という形式でしか存在できません**。なので、例えば以下のコードはSnytax Errorになります。
+
+```ruby
+a = { |e| e + 1 }
+a = do |e|
+ e + 1
+end
+```
+
+## ブロック付きメソッド呼び出し
+
+メソッドがブロックを受け取る方法を説明します。
+
+### `yield`
+
+1つ目のやりかたは、`yield`を使うことです。
+
+例:
+
+```ruby
+def hoge
+ yield(100)
+end
+
+hoge { |e| e + 1 } # => 101
+```
+
+ちょっと分かりづらいですが、`yield`がブロックを「起動」していると思ってください。`yield`の引数がブロックの引数になります。
+
+### `&block`
+
+2つ目のやりかたは、`&block`引数を使うことです。
+
+```ruby
+def hoge(&block)
+ block.call(100)
+end
+
+hoge { |e| e + 1 } # => 101
+```
+
+このように`&block`という引数を宣言すると、ブロックが`block`変数に代入されます。そして、`block.call`メソッドを呼ぶと、ブロックの処理が実行されます。直感的ですね。
+
+## ブロックオブジェクト(`Proc`)
+
+「さっき『ブロックは変数に代入できない』って言ったじゃん!」と思った人がいると思います。
+実は`block`に入っているのはブロックではなく「ブロックオブジェクト」です。
+
+ブロックオブジェクトの正式名称は`Proc`といって、以下のように生成できます。
+
+```ruby
+blk1 = Proc.new { |e| e + 1 }
+blk1.call(100) # => 101
+
+blk2 = proc { |e| e + 2 }
+blk2.call(100) # => 102
+```
+
+`Proc`は普通のオブジェクトなので、変数に代入できます。
+つまり、メソッドが`&block`変数でブロックを受けると、上のような処理が走ってブロックをオブジェクトにしているということですね。
+
+## `Proc`からブロックへの変換
+
+`Proc`をブロックとしてメソッドに渡したい気持ちになることがあります。
+
+```ruby
+plus_100 = proc { |e| e + 100 }
+[1,2,3].map(plus_100) # => Error!
+```
+
+しかしこれはエラーになります。なぜなら`plus_100`はProcオブジェクトであってブロックではないからです。
+
+Procオブジェクトをブロックに変換するためには`&`を使います。
+
+```ruby
+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)`