Edited at

Enumerator::LazyはEnumerable#injectを使用できる

More than 3 years have passed since last update.

Enumerator::Lazyの継承関係を理解できていませんでした。。

以下にまとめました。


①Enumerator::Lazy#takeで指定した数のEnumerator::Lazyオブジェクトを取得



p (1..Float::INFINITY).lazy.map { |i| i ** 2}.take(3)

# =>#<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 1..Infinity>:map>:take(3)>


②Enumerator::Lazy#forceで配列を取得



p (1..Float::INFINITY).lazy.map { |i| i ** 2}.take(3).force

# =>[1, 4, 9]


③配列に対してEnumerable#injectの実行



p (1..Float::INFINITY).lazy.map { |i| i ** 2}.take(3).force.inject(0,&:+)

# => 14


④Enumerator::Lazyに対してEnumerable#injectの実行

③と同じ結果。Enumerator::Lazy#forceは不要であると分かる。



p (1..Float::INFINITY).lazy.map { |i| i ** 2}.take(3).inject(0,&:+)

# => 14


まとめ

Enumerator::Lazyオブジェクトに対してinjectメソッドを呼ぶと例外が発生するかと思っていましたが間違いでした。

Enumerator::Lazy#forceで配列に戻してからでないと、injectメソッドを使用することができないと思っていましたがそんなことはなく、Enumerator::LazyはEnumerableモジュールを継承しているので、配列に戻さなくてもそのままEnumerable#injectを使用できました。


参考リンク


instance method Enumerator::Lazy#take

http://docs.ruby-lang.org/ja/2.1.0/method/Enumerator=3a=3aLazy/i/take.html

take(n) -> Enumerator::Lazy


Enumerable#take と同じですが、配列ではなくEnumerator::Lazy を返します。

n が大きな数 (100000とか) の場合に備えて再定義されています。 配列が必要な場合は Enumerable#first を使って下さい。


[PARAM] n:

要素数を指定します。

[EXCEPTION] ArgumentError:

n に負の数を指定した場合に発生します。

[SEE_ALSO] Enumerable#take



instance method Enumerator::Lazy#force

http://docs.ruby-lang.org/ja/2.1.0/method/Enumerator=3a=3aLazy/i/force.html

force(*args) -> [object]


全ての要素を含む配列を返します。Lazy から実際に値を取り出すのに使います。

Enumerable#to_a のエイリアスです。



instance method Enumerable#inject

http://rurema.clear-code.com/2.1.0/method/Enumerable/i/inject.html

以下の通り、Enumerator::LazyEnumerableモジュールを継承しているのでEnumerable#injectを使用できる。

pry(main)> Enumerator::Lazy.ancestors

=> [Enumerator::Lazy, Enumerator, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject]


引用元:

クラスの継承関係

EnumeratorとEnumerator::Lazyの違い



参考にしたツイート

以下のツイートにインスパイアされて記事を書きました。

参考: 武田哲也さんのRuby技術者認定試験受験記


補足: Enumerator::Lazy は2.0からですが、 Enumerable#take は1.8.7から入っています。

http://ref.xaio.jp/ruby/classes/enumerable/take