LoginSignup
1
0

More than 5 years have passed since last update.

IOオブジェクトでtake_whileするときは副作用に注意

Posted at

Enumerable#take_whileは、公式リファレンスによると

Enumerable オブジェクトの要素を順に偽になるまでブロックで評価します。 最初に偽になった要素の手前の要素までを配列として返します。

というメソッドです。
つまり、たとえば戻り値が長さ4の配列だった場合、5つ目の要素までeachで評価しているということになるわけです。

普通はそれで問題ないわけですが、IOオブジェクトのようにeachメソッドに副作用があると少し変わってきます。
IO#eachは1行ごとに読んでポインタを進めますから、以下のようなことが起こります。

$ seq 1 10 | ruby -e 'p $stdin.take_while {|i| i.to_i < 5}; p $stdin.gets'
["1\n", "2\n", "3\n", "4\n"]
"6\n"

seq 1 10で1から10までの数字を1行ずつRubyの標準入力に渡しています。
最初のtake_whileで1から4までを取ったので、次のgetsでは5が得られるような気がするんですが、5はtake_whileで読み込まれて捨てられているので、次の6が出力されます。

1
0
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
1
0