どうも、最近は勤怠プロダクトの開発に勤しんでいる @Joharu です。
ごく基礎的な内容になりますが、
業務でRubyの範囲型 (Range
)を取り扱う際に躓いたので、記事にしてみます。
(自論に近いので、怪しい点などあれば是非コメント頂けると嬉しいです🙇♀️)
TL;DR
- Rubyの
Range
から先頭要素を取得する時はfirst
よりbegin
がおすすめ -
first
は..Date.today
みたいな無限範囲でRangeError
になる -
begin
ならnil
が返ってきてもエラーにならない
環境
- Ruby 3.0以降(無限範囲記法
..
が使用可能)
躓いたこと:firstだとエラーになることがあった
Rangeの先頭を取りたい時、first
を使っている箇所があったのですが、
実はこれが起因のエラーを踏むことがありました。
# 普通の範囲なら問題なし
(1..10).first # => 1
(1..10).begin # => 1
# でも無限範囲だと...
(..Date.today).first # => RangeError - cannot get the first element of beginless range
(..Date.today).begin # => nil(エラーにならない)
..Date.today
みたいな書き方、日付の範囲処理でよく使いますよね。
でもfirst
だとRangeError
になっちゃうんですね。
実際にありがちなケース
こんなコードを書いたことありませんか?
# 期間を指定して何かを処理する関数
def process_data_in_period(date_range)
start_date = date_range.first # ここでエラーになる可能性
# ...
end
# 「今日まで」の範囲を渡すとエラー
process_data_in_period(..Date.today) # RangeError!
これをbegin
に変えるだけで安全になります:
def process_data_in_period(date_range)
start_date = date_range.begin # nilが返ってもエラーにならない
return if start_date.nil? # nilチェックも簡単
# ...
end
process_data_in_period(..Date.today) # 正常に動作
なぜbeginの方がいいのか
begin
を使うメリットは単純です:
-
RangeError
にならない: 無限範囲でもnil
が返るだけ -
nilチェックしやすい:
nil
かどうかで無限範囲を判定できる
以上!
まとめ
Range型から先頭を取る時はbegin
を使うのがおすすめ、という話でした。
理由は簡単で、nil
があってもRangeError
にならないから。
特に..Date.today
のように無限範囲になる可能性がある箇所は、begin
を使っておけば安心ですね。
参考記事