LoginSignup
4
4

More than 5 years have passed since last update.

Kernel.#loopにEnumerator#with_indexを付けるときの注意点

Posted at

結論

ブロックパラメータには Kernel.#loop のパラメータも用意すること。
というか、Enumerator#with_index がレシーバに対応するブロックパラメータをも必要とする、ということ。

pry(main)> loop.with_index { |_, i| puts i; sleep 1 }
0
1
2
3
^CInterrupt: 

_Kernel.#loop のパラメータ、iEnumerator#with_index のパラメータです。

経緯

ループしながら待ち時間を徐々に長くするにはどうすれば良いかな、と思ったのがきっかけです1
さて、試しに

loop.with_index do |i|
  p i
  sleep 1
end

を実行してみると nil しか返ってきません。
Kernel.#loopEnumerator を返すはずなのになあ、と思いつついろいろいじくりました。

最終的に、次のようにしたときに気付きました。

pry(main)> l = loop.with_index
#=> #<Enumerator: ...>
pry(main)> l.next
#=> [nil, 0]
pry(main)> l.next
#=> [nil, 1]
pry(main)> l.next
#=> [nil, 2]
pry(main)> l.next
#=> [nil, 3]

ああ、なるほど Enumerator#with_index のレシーバである Kernel.#loop に対応するブロックパラメータ(ここではブロックを付けていないので nil)も必要なんだ、と分かったわけです。

るりま

module function Kernel.#loop

loop -> Enumerator
loop { ... } -> object | nil
(中断されない限り)永遠にブロックの評価を繰り返します。 ブロックが指定されなければ、代わりに Enumerator を返します。
module function Kernel.#loop (Ruby 2.3.0)

instance method Enumerator#with_index

with_index(offset = 0) {|(*args), idx| ... } -> object
with_index(offset = 0) -> Enumerator
生成時のパラメータに従って、要素にインデックスを添えて繰り返します。 インデックスは offset から始まります。
ブロックを指定した場合の戻り値は生成時に指定したレシーバ自身です。
生成時のパラメータに従って、要素にインデックスを添えてブロックを繰り返します。 インデックスは 0 から始まります。
instance method Enumerator#with_index (Ruby 2.3.0)


  1. 結論としては、例えば loop.with_index { |_, i| do_something; break if break_condition; sleep 10 * i } となります。 

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4