と、なると気になるのはeachの挙動ですよね
昨日の続きです。
さて、またまたRubyの実装を見て見ることにしましょう。
今度はeachがどのように実装されているのでしょうか。Array#eachは以下のように実装されています。
/*array.c 1742行目*/ VALUE rb_ary_each(VALUE array) { long i; volatile VALUE ary = array; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(RARRAY_AREF(ary, i)); } return ary; }
ループを回す際に毎回配列のサイズを求めているようですね。Rubyの配列は範囲外の値を得ようとするとnilが返ってきますが、Cでそんなことをするとプログラム自体がコケてしまうので当たり前といえば当たり前。なので要素が増えたり減ったりすると早く止まったり止まらなかったりするわけですね。
RARRAY_AREF(ary, i)
は、aryが指している配列を得て、その配列のi番目の要素を返すマクロのようです。安直に考えれば
(*ary)[i]とそう大差ないことをやっているような気もしないでもありません。もちろんマクロを展開したところでこのような式にたどり着くわけではありませんが。
ということで、配列に何かひとつずつunshiftしていくと、ずっと元々の最初の要素を延々とブロックに渡し続けることになります。なるほど、unshiftで止まらない理由に納得がいった。