无开始日期范围不允许包含?

Con*_*hen 1 ruby ruby-2.7

ruby 2.7 引入了无限范围。现在您可以拥有:

(..5)
(5..10)
(10..)
Run Code Online (Sandbox Code Playgroud)

对于整数,.include?可以按预期工作:

(..5).include?(6) # false
(..5).include?(5) # true
(..5).include?(2) # true
(..5).include?(-100) # true
Run Code Online (Sandbox Code Playgroud)

但是,这不适用于日期范围:

(..Date.tomorrow).include?(Date.today) # RangeError (cannot get the first element of beginless range)
Run Code Online (Sandbox Code Playgroud)

有趣的是,它的作用相反:

(Date.yesterday..).include?(Date.today) # true
Run Code Online (Sandbox Code Playgroud)

最后:

(Date.yesterday..).include?(Date.today - 2.days) # Seems to loop forever.
Run Code Online (Sandbox Code Playgroud)

这是一种很奇怪的行为。所有 3 个案例都会带来不同的结果,并且只有其中 1 个案例真正按预期工作。

我的意思是,我想如果我们有一个具有某种“连续”逻辑的范围,那么可能很难检查是否包含在内,这是可以理解的。但像 Date 这样相对简单的类至少应该可以工作。无论如何,日期几乎就像一个整数。甚至 Float 也可以做到这一点,所以我不明白为什么 Date 或 DateTime 不应该这样做。

我的用例是数据库可能会为我正在查询的 2 个日期提供 nil 。这些是我想在一个范围内使用的开始和结束日期,但我不能确定其中一个可能不为零,这对我的逻辑来说很好,但这会导致一个无开始的范围,这可以处理不了.include?

我可以轻松地让我的用例通过一些手动丑陋的检查来工作,但这不是优雅的 ruby​​ 方式。我在这里错过了什么吗?或者这应该是一个尚不存在的功能?

Hol*_*ust 6

使用Range#include?,您实际上是在迭代范围,比较范围中的每个元素是否等于测试元素。仅对于数字范围,这会在内部进行优化,以按照您明显期望的方式运行。引用文档

true如果obj是范围内的元素则返回,false否则返回。如果beginend是数字,则根据值的大小进行比较。

因此,Range#include?您可能不想在这里使用Range#cover?仅检查范围的边界(并且其工作方式与Range#include?仅使用数字边界相同):

true如果obj位于范围的begin和之间,则返回。end

这测试begin <= obj <= end何时exclude_end?isfalsebegin <= obj < end何时exclude_end?is true

[...]

false如果begin范围值大于该值则返回endfalse如果内部调用之一返回<=>nil表明对象不可比较),也会返回。

根据您的示例,Range#cover?做正确的事情:

(..Date.tomorrow).cover?(Date.today)
# => true

(Date.yesterday..).cover?(Date.today)
# => true

(Date.yesterday..).cover?(Date.today - 2.days)
#  => false
Run Code Online (Sandbox Code Playgroud)