Rubyのprocとかyieldとか
本を読んだだけでは理解できなかったので、一度いろんな記事を斜め読みしてみることにする。
一度目にして理解できない概念は、いろんな切り口とか言い回しで書かれた記述を総当たりしていくと理解が早い。
参考リンクをみていると、ブロックの概念とブロックの使い方は分かっている気がする。 ブロックとは
Rubyではdo ~ endの一塊(処理の塊)をブロックと言う。
do ~ endの代わりに{ ~ }を使うことも可能。
ブロックは、単独では存在できない
問題はその先の、yield以降だ。
ブロック付きメソッド??
引数なしのブロック付きメソッドの作り方 ― yieldメソッドの使い方
以下の例は、"red"、"green"、"blue"という文字列を順に返すだけのcolorEnumメソッドの作成例と利用例である。colorEnumメソッドの中では、yieldメソッドの引数にブロックパラメーターに渡す値を指定する。繰り返しの回数はyieldメソッドが呼び出される回数と考えればよい。
yieldもメソッド。
yieldをコードで確認する
code:yield
def colorEnum # colorEnumメソッドを定義する
yield "red"
yield "green"
yield "blue"
end
# 実用的なプログラムを作るときには、上のプログラムのようにyieldメソッドをいくつも書くのは現実的ではない。
# そのためには、メソッド定義の中で繰り返し処理(や、他のブロック)を使えばいい。
colorEnum do |x| # colorEnumメソッドを呼び出す
puts x
end
引数ありのブロック付きメソッド
code:yield2
def makeodd(limit) # makeoddメソッドを定義する
for i in 0..limit-1
yield 2 * i + 1 # forを使って繰り返しyieldを呼び出す
end
end
makeodd(5){|x| # makeoddメソッドを呼び出す
puts x
}
ブロックを引数として渡すことも可能
ブロック引数を受け取る関数を定義するには&blockという仮引数を書く。ただしブロック引数は1つしか受け取れない。引数の最後の1つとして書かなければならない。
&blockで引数を渡す→呼び出すときはblock.call(ブロックの引数)
code:&block
def receive_block(i, j, &block) # 後述:ここの&blockはブロックを表している
puts "受け取ったブロックを実行します"
block.call(i, j) # 後述:ここのblockはProcインスタンス
puts "実行しました"
end
receive_block 2, 3 do |i, j|
end
受け取ったブロックを実行します
2 + 3 = 5
実行しました
mochi5o.icon分かったような、分からんような。コードにすると読めない事はないけど空で意味を言えって言われるとまだ無理な気がする
Procとは
処理の塊をオブジェクト化したもの。処理の塊であるブロックをProcクラスのコンストラクタに渡すことで、Procインスタンスを作ることができる。
Procクラスをnewする(インスタンスを作る)と、処理の塊をオブジェクトにできる=変数に代入できる
この辺り処理の塊を変数に突っ込んで使えるみたいなのってjsと同じような感じか…
呼び出すときはcallメソッド。Procオブジェクトは引数も取れる
code:proc
proc = Proc.new do
puts "Hello proc"
end
proc.call
Hello proc
proc = Proc.new do |message|
puts message
end
proc.call("Hello proc")
Hello proc
ここで結構整理してくれている
ブロック引数を受け取る宣言として使う&blockと、関数定義部分のblockは、ブロックとProcインスタンスの関係であり、内部的に受け取ったブロックをProcインスタンス化している。
&はブロックを表す記号であり&blockのblockはブロック引数につけた仮引数名にあたるので実は何でも良い。
つまり引数として受け取ったblockという名のブロックを、blockという名のProcインスタンスに変換しているからblock.callで実行することができる。
なるほど。で、さらにRubyらしいというか、より簡単にシュッと書くことができる仕組みがある。
そもそもブロック引数を1つしか受け取れないんだったら、ブロック引数に名前を付ける意味なくね?いちいちblock.callなんて無駄にインスタンス名書かせんなよ。ってことで、Procインスタンスの実行部分(block.call)はyieldで置き換えられる。
結局どのように省略されていったかの経緯を追うのが一番分かりやすかった→この記事 あと、上記の記事の途中でjsのことを思い浮かべながら読んだのだが、正しくjsとの対比で記述している記事を見つけた
シンタックスシュガーであるという表現でまた一つ、なるほどとなった。
ここで書籍に戻る。