せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】Enumeratorクラス、pメソッドで出力されるもの

勉強ブログ(勝手に命名)、
http://melborne.github.io/2012/02/08/2-12-Ruby-12-Trivia-Notations-you-should-know-in-Ruby/
に、

loopにブロックを渡さないとEnumeratorが返るんだよ。
・・・
timesはブロックを渡さないとEnumeratorを返すよ。

と書いてあった。どういうことだろう。


 

Enumrableとは

「初めてのRuby」2章3にはこうある↓

Enumrableはこのようなeachメソッドから
導入可能なメソッドを集めたモジュールです

なるほど。「eachメソッドを持っている」ことがポイントなんだ。
つまりそれは、「各要素を順番にぐるぐる回せる」ってことか。
「列挙用のメソッド」と言うらしい。
Enumratorは、
「どんな風にぐるぐる回すのか(1個とび、とか。
ある条件に当てはまるものだけ、とか)」を自由に定義するためのクラス。
  

 
「初めてのRuby」7章3.3にはこうある↓

Ruby1.9では、イテレーターをブロックなしで呼び出すと、
そのイテレーターをラップしたEnumeratorを生成して返します。

なるほど。
しかしこれは仕様ではなく、そういう形で標準ライブラリが実装しているだけにすぎない。
自分で独自にイテレーターを定義した場合は、この実装を満たすように作る必要がある。

結局さっきの発言は、イテレータ全般にいえる事、なのか。なるほど。

loopにブロックを渡さないとEnumeratorが返るんだよ。
・・・
timesはブロックを渡さないとEnumeratorを返すよ。

 

timesは内部カウンタが取れる

map = 5.times.map do |st|
	st.to_s + "jj"
end
p map

■実行結果

["0jj", "1jj", "2jj", "3jj", "4jj"]

内部カウンタが取れるんだ?調べてみると「初めてのRuby」6章に書いてある↓

times
このメソッドは内部カウンタをブロックに引き渡してくれるので、
カウンタを利用することも可能です。

なるほど。

 
まだまだEnumeratorクラスって良く分からない。
調べてみよう。

class Hoge
end
p Hoge.new
p enum = Enumerator.new("abc")
p enum = 3.times

■実行結果

#<Hoge:0x30a03b0>
#<Enumerator: "abc":each>
#<Enumerator: 3:times>

ん?
クラス名をキーとした値が、
普通のクラスオブジェクトの時と見え方が違う。

そもそもこの、pメソッドで出力される文字列って何なんだ?


 

pメソッドで出力される文字列

pメソッドは、・・・inspectメソッドの結果に改行を加えて出力します。

http://ref.xaio.jp/ruby/classes/kernel/p

なるほど。

Enumerator#inspectメソッドが上書きされている、ということか。
公式ドキュメントを当たってみても記載はない。

 
調べてみると、
どうも2008年に「えんどうゆうすけ」さんが提案した案みたいだ↓

Enumerator の中身をわかりやすく表示してくれる Enumerator#inspect を提供すると便利だと思います。
現状は #<Enumerator:0x8269654> とかなので、デバッグには不便です。
・・・
 
実際の中身よりもそのEnumeratorオブジェクトがどこから出てきたのかがわかる方が嬉しいような気がします。
(1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>
という感じでどうでしょうか。

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/37264

へー。
こんないきさつで仕様が決まってるんだ。

面白いなー。