忍者ブログ

ぢみへんプログラミング日誌

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

Enumerator がなんで必要なのかようやく分かった

RubyにはEnumeratorというEnumerableモジュールのラッパークラスと呼ばれるクラスがあるのだが、これはeachメソッドを実装してないクラスにもEnumerableモジュールの機能を与えるためのインターフェイスクラスとして存在しているということを今日初めて理解した。


class Abc
def initialize
@arr = []
end

def set_num(num)
@arr << num
end

def my_each
@arr.each do |num|
yield num
end
end
end

abc = Abc.new

abc.set_num 100
abc.set_num 200
abc.set_num 300
abc.set_num 1000
abc.set_num 10000

abc.my_each { |i| p i}

enum = Enumerator.new(abc, :my_each)

m = enum.map{|i| i*i}

p m


このコードの実行結果は以下の通りとなる。

> ruby enumerator_experiment.rb
100
200
300
1000
10000
[10000, 40000, 90000, 1000000, 100000000]


見ての通り、クラスAbcはEnumerableをincludeしていないのでEnumerableで定義されているmapやsellect等のメソッドをAbcは使えない。また仮にEnumerableをincludeしていたとしても、Abcにはeachメソッドがないから機能しない。こういうクラスにEnumerableのインターフェイスを与えてやるにはどうしたらいいのか。

そこでEnumeratorの出番というわけだ。クラス独自のイテレータメソッドを持っていれば、それをeachの代わりとみなしてEnumerableの各メソッドを実行させてしまおうという意図で使うことができる。EnumeratorクラスのメソッドインターフェイスはEnumerable互換であると考えてよい。
上記コード例で行くと、Abc#my_eachは自作のeachメソッドで内部実装自体にはArray#eachを使っている。Enumerator::new でこのメソッドを指定すると生成されたEnumeratorオブジェクトの各メソッドは、Enumerableモジュールの各メソッドがinclude元クラスのeachメソッドを基盤に動作するのと同じように、Abc#my_eachの実装を基にmapやsellectメソッドを構築する。


さて、Ruby1.9からはeachメソッドにブロックが続かなかったときは、eachメソッドの戻り値がEnumeratorとなる。そのため次のようなコードが書ける。


irb(main):003:0> [1,2,5,100,10].each
=> #
irb(main):004:0> [1,2,5,100,10].each.zip([2,4,6,8,10])
=> [[1, 2], [2, 4], [5, 6], [100, 8], [10, 10]]


これと同じ挙動を先のmy_eachに加えられるだろうか?
block_given? メソッドを使ってブロック判定を行い、ブロックがなければEnumeratorば可能だ。


class Abc
def initialize
@arr = []
end

def set_num(num)
@arr << num
end

def my_each
if block_given?
@arr.each do |num|
yield num
end
else
Enumerator.new(self, :my_each)
end
end
end

abc = Abc.new

abc.set_num 100
abc.set_num 200
abc.set_num 300
abc.set_num 1000
abc.set_num 10000

abc.my_each { |i| p i}

enum = Enumerator.new(abc, :my_each)

m = enum.map{|i| i*i}

p m

m = abc.my_each.map{|i| i*2}

p m


実行結果:

> ruby enumerator_experiment.rb
100
200
300
1000
10000
[10000, 40000, 90000, 1000000, 100000000]
[200, 400, 600, 2000, 20000]
PR

COMMENT

NAME
TITLE
MAIL (非公開)
URL
EMOJI
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
COMMENT
PASS (コメント編集に必須です)
SECRET
管理人のみ閲覧できます
 
  

カレンダー

10 2024/11 12
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

フリーエリア

最新CM

バーコード

ブログ内検索

Copyright ©  -- ぢみへんプログラミング日誌 --  All Rights Reserved

Design by CriCri / Material by petit sozai emi / powered by NINJA TOOLS / 忍者ブログ / [PR]