💣

rubyのrangeで終端がnilになると無限ループ

2022/07/30に公開

https://docs.ruby-lang.org/ja/latest/class/Range.html

rubyでrangeを作る時、始端や終端をnilにすることができるようなのですが、ループの挙動が面白かったので記事にします。

# 終端のないrange
range = (0..nil)
range.cover? 9999             # true
range.cover? -1               # false
range.each {|n| p n }         # 無限ループ(nが表示される)
range.reverse_each {|n| p n } # 無限ループ(何も表示されない)

# 始端のないrange
range = (nil..10)
range.cover? -9999            # true
range.cover? 11               #false
range.each {|n| p n }         # RangeError: cannot get the first element of beginless range
range.reverse_each {|n| p n } # RangeError: cannot get the first element of beginless range

今回は終端を動的に取得していてそれがnilが変えるシチュエーションがあり無限ループしました。

(0..children_depth).reduce ...

children_depthが対象のテーブルにレコードが一つもない時nilが返ると言うのを気づかずにハマりました。終端が動的な時は注意が必要かと思います。

reverse_eachはどちらも予想外な感じですね・・・

https://ruby-doc.org/core-3.1.1/Enumerable.html#method-i-reverse_each

ソース見てみたけど、ここだけだと不明。ary = enum_to_a(argc, argv, obj);の中で何かが起こってるのかな?

試したrubyは下記です。
ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc)

Discussion