チェリー本 4章 その2

ブロック

rubyでも出てきたが
いまいちよくわかっていないのが現状です。
ここでしっかり概念を抑えていきたいと思います。

ブロックとは...
メソッドの引数として渡すことができる処理の塊。
ブロック内で記載した処理は必要に応じてよばれる。

ここでは参考として
rubyの特徴を記載します。
繰り返し処理の場合...

他の言語(javaとかCとか)は繰り返し処理は基本的にfor文を使い
プログラムがコンピューターに対して処理を明示的に命令している。

一方でruby

繰り返しメソッド(each、timesとか)を使うのが主流。
もちろんrubyでもfor文は存在する。

  • 他の言語(Javaとかc)は各言語機能として繰り返しを行っている
  • rubyはメソッドを使っている。

ここではeachメソッドを使っています。
eachメソッドの役割は配列の要素を最初から最後まで取り出す作業をしてくれる。
さっき出てきたブロックが do~endのこと。

numbers = [1, 2, 3, 4]
sum = 0

numbers.each do |n|
  sum += n
end

puts sum
=> 10

|n|のことををブロック引数と言う。
ここにeachで取り出した1,2,3,4が渡ってくる。

ブロックの引数は使わない場合は省略できる。

ブロックを使用する際は気をつけないといけないことがある。
例えば
このような下のコードが存在する時
この式は

配列を順番に取り出す
ブロック内の処理は
条件演算子
偶数の場合10倍する、奇数の場合そのまま
それらを最終的に足し算する式が存在する。

numbers = [1, 2, 3, 4]
sum = 0
numbers.each do |n|
  sum_value = n.even? ? n * 10 : n
end
p sum

=>
64

ブロックにはスコープという有効範囲が存在する。
仮にスコープ内のsum_valueを呼んでみる。

numbers = [1, 2, 3, 4]
sum = 0
numbers.each do |n|
  sum_value = n.even? ? n * 10 : n
  p sum_value
end

#スコープ内の為呼び出しに成功している。
=>
1
20
3
40


#スコープ外で呼び出すと
numbers = [1, 2, 3, 4]
sum = 0

numbers.each do |n|
  sum_value = n.even? ? n * 10 : n
end

p sum_value
=>
Traceback (most recent call last):
lib/ch_4.rb:8:in `<main>': undefined local variable or method `sum_value' for main:Object (NameError)

スコープの外と中では世界が違う
逆にスコープの外で作られた変数は使える。

ブロック引数の名前をブロックの外にある変数と同じ名前にすると
ブロック内では引数の値が優先して使われる。

名前の重複により他の変数が使えなくなることをシャドーイングという。
混乱を招くので使わない方がいい

do...endと{}

今まではブロックを記載するときは改行を入れていたが一行で書くこともできる。

numbers = [1, 2, 3, 4]
sum = 0
numbers.each do |n| sum += n end
p sum

=>10


すごい見にくい

ブロックの記載には
do~endを使う代わりに{}を使って書くこともできる。

numbers = [1, 2, 3, 4]
sum = 0
numbers.each { |n| sum += n }
p sum
=>
10

#もちろん改行も使える
numbers.each { |n|
  sum += n
}
p sum
=>
10

使い分けは

do...end {}で記載する時は
改行を含む長いブロックを書くとき 一行でコンパクトに書きたいとき

今後もどんなときにブロックが便利か勉強していきます。