4

我试图了解如何range.cover?工作和遵循似乎令人困惑 -

  1. ("as".."at").cover?("ass") # true("as".."at").cover?("ate") # false

    这个孤立的例子并不令人困惑,因为它似乎是ass在.atate

  2. ("1".."z").cover?(":") # true

    这个事实似乎是基于 ASCII 值而不是字典样式,因为在字典中我希望所有特殊字符都在偶数之前,而混乱从这里开始。如果我认为是真的,那么如何cover?决定采用哪种比较方法,即使用 ASCII 值或基于字典的方法。

  3. 以及范围如何与数组一起使用。例如 -

    ([1]..[10]).cover?([9,11,335]) # true

    这个例子我预计是错误的。但从表面上看,在处理数组时,边界值和cover?' 参数都被转换为字符串,并且简单的字典样式比较会产生 true。这是正确的解释吗?

  4. 可以处理什么样的物体Range?我知道它可以numbers(除了复杂的),handle strings,能够神秘地使用,arraysboolean, nil and hash其他值会导致它提高ArgumentError: bad value for range

4

1 回答 1

4

为什么会([1]..[10]).cover?([9,11,335])返回true

让我们看一下源码。在 Ruby 1.9.3 中,我们可以看到以下定义。

static VALUE
range_cover(VALUE range, VALUE val)
{
  VALUE beg, end;

  beg = RANGE_BEG(range);
  end = RANGE_END(range);
  if (r_le(beg, val)) {
    if (EXCL(range)) {
      if (r_lt(val, end))
        return Qtrue;
    }
    else {
      if (r_le(val, end))
        return Qtrue;
    }
  }
  return Qfalse;
}

如果范围的开头不小于或等于给定值,则cover?返回false。这里小于或等于是根据函数确定的,该r_lt函数使用<=>运算符进行比较。让我们看看它在数组的情况下如何表现

[1] <=> [9,11,335] # => -1

所以显然[1]确实小于[9,11,335]。于是我们进入了第一个身体if。在内部,我们检查范围是否不包括其结尾并再次使用<=>运算符进行第二次比较。

[10] <=> [9,11,335] # => 1

因此[10]大于[9,11,335]。该方法返回true

为什么你看到ArgumentError: bad value for range

负责引发此错误的函数是range_failed. range_check它仅在返回 a时调用nil。什么时候发生?当范围的开始和结束无法比较时(是的,再次就我们亲爱的朋友,<=>运营商而言)。

true <=> false # => nil

true并且false是无法比拟的。范围不能被创建并且ArgumentError被提升。

最后,Range.cover?对 的依赖<=>实际上是一种预期和记录在案的行为。请参阅RubySpec.cover?

于 2012-10-19T18:52:29.757 回答