Edited at
移行Day 10

AdventCalendar Day10 [超Ruby入門]


はじめに

本記事は、超Ruby入門10日目の記事です。

コメント頂ける方は、ガイドラインを読んで頂けると幸いです。


本題

%w[Ruby, Python, PHP].map { |str| str.length }

map { } というコードを見たことはないだろうか。

p Enumerator.method_defined?(:map)

> true

mapはEnumeratorオブジェクトのメソッドだ。


各要素に対してブロックを評価した結果を全て含む配列を返します。

ブロックを省略した場合、上で説明した繰り返しを実行し、その結果として 得られる配列を返すような Enumerator オブジェクトを返します。Enumerableモジュール


ブロックとは何なのだろうか?


ループを構成したり、家や塀を建てたり、人を殴ったりするもの。

Ruby用語集


block.jpg

ブロックは、Rubyで最も利用する構文だ。

さてここで問題だ。

以下コードのどこにブロックが隠れているだろうか。

%w[Ruby, Python, PHP].map { |str| str.length }

正解は、{ } の部分だ。

{ |str| str.length }

ブロックはブロック付きメソッド呼び出し(イテレータ)と共によく利用される。

イテレータの文法が複数存在することをご存知だろうか?

method(arg1, arg2, ...)  do [`|' 式 ... `|'] 式 ... end

method(arg1, arg2, ...) `{' [`|' 式 ... `|'] 式 ... `}'
method(arg1, arg2, ..., `&' proc_object)

上記のように3つの文法がある。今まで見たのは真ん中の文法だ。

ブロック構文{}の代わりにdo ~ endを使うと下記コードとなる。

%w["Ruby", "Python", "PHP"].map do |str|

str.length
end


イテレータはループのようにみえる。

ループと言えば、for構文を思い浮かべるのではないだろうか?

では、for構文とイテレータの差異を調べてみよう。

# for

for i in [1, 2, 3, 4, 5]
for_last = i
end
puts "for #{for_last}"

# iterator
[1, 2, 3, 4, 5].each do | num |
last = num
end
puts "iterator #{last}"

上記コードを実行するとイテレータがエラーとなる。

そう!for構文とイテレータではスコープが違うのだ。

ブロックは新しいローカル変数を持つが、 for文はローカル変数のスコープに影響を及ぼさない。

もう、mapが何を行なっているのか理解できたのではないだろうか?

%w[Ruby, Python, PHP].map { |str| str.length }


mapメソッドをクリアして疲れた頃だろうか。

大丈夫、次が最後だ。yieldのついてみていこう。

ああ、読み方か。イールドだ。

yieldは、自分で定義したイテレータでブロックを呼び出す時に使う。

わけがわからないので、コードをみよう。

def check_yield

yield
end

check_yield { puts "pass check_yield" }

check_yieldメソッドを呼び出すとyieldはブロックを呼び出している。

次に、yieldに引数を渡してみよう。

def check_yield_argvs

yield(1)
end

puts check_yield_argvs { | x | x + 2 }

yield(1)の1はどこに代入されるのだろうか。

正解は、ブロックパラメータだ。

check_yield_argvs { | block_parameter | x + 2 }

ブロックの説明は以上!


時間があるできた時にやること

yield(self)