为什么字符串 '3' 在范围为 ('0'...'10') 的 case 语句中不匹配?

joc*_*ode 34 ruby

当我尝试在 case 语句中匹配字符串 '3' 时,它匹配范围是否达到 '9',而不是 '10'。

我猜它与三重等号运算符有关,但我不知道它可以在范围内但不匹配的确切原因。

这是一个 IRB 运行,记录了有效(使用“9”)和不起作用(使用“10”)的两种情况:

 case '3'
 when ('0'...'9')
     puts "number is valid"
 else
   puts "number is not valid"
 end
Run Code Online (Sandbox Code Playgroud)

输出: number is valid

 case '3'
 when ('0'...'9')
     puts "number is valid"
 else
   puts "number is not valid"
 end
Run Code Online (Sandbox Code Playgroud)

输出: number is not valid

我用作预期结果参考的方法是
Enumerable#include?
Enumerable#member?
,查看转换为数组时输出的内容是 ( Enumerable#to_a)。

“大小写相等” ( ===) 运算符的结果让我感到惊讶。

 case '3'
 when ('0'...'10')
     puts "number is valid"
 else
   puts "number is not valid"
 end
Run Code Online (Sandbox Code Playgroud)

3li*_*t0r 42

范围cover?用于大小写相等。所以它正在比较'3' >= '0' && '3' < '10'哪个结果false因为'3' < '10' #=> false。字符串基于字符值进行比较。

为了更好地理解,您可能希望将字符串视为字符数组:

['3'] <=> ['1', '0'] #=> 1 (first operand is larger than the second)
Run Code Online (Sandbox Code Playgroud)

要解决此问题,请将case输入转换为整数并使用整数范围:

case 3 # or variable.to_i
when 0...10
  puts 'number is valid'
else
  puts 'number is invalid'
end
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为整数不是基于字符代码进行比较,而是基于实际值。3 >= 0 && 3 < 10结果在true.

或者,您可以通过不传递范围而是传递一个方法来明确告诉何时使用member?(or include?) 方法。

case '3'
when ('0'...'10').method(:member?)
  puts 'number is valid'
else
  puts 'number is invalid'
end
Run Code Online (Sandbox Code Playgroud)

  • @jockofcode [方法的大小写相等](https://ruby-doc.org/core-3.0.1/Method.html#method-i-3D-3D-3D) 使用大小写参数/输入调用方法。因此,将 `range.method(:member?)` 传递给 *when* 可以使用 `range.method(:member?) === input` -&gt; `range.method(:member?).call(input)` 来解析它而仅提供 `range` 将导致 `range === input` -&gt; `range.cover?(input)` (2认同)
  • @jockofcode 在这个特定场景中,还可以选择使用 `'0'..'9'` (两个点而不是三个,请参阅 [`Range`](https://ruby-doc.org/core- 3.0.1/Range.html)文档)。但这仅在您期望单个数字时才有效。这类似于正则表达式“[0-9]”。 (2认同)

Sil*_*olo 17

===说它等效于cover?,后者的文档说明它等效于

begin <= obj < end
Run Code Online (Sandbox Code Playgroud)

所以,在你的情况下,我们得到

'0' <= '3' < '10'
Run Code Online (Sandbox Code Playgroud)

并且<=<使用字典顺序比较字符串,所以比较是错误的。

另一方面,我们必须做更多的挖掘才能弄清楚member?/include?实际做什么(两者是等价的)。如果我们查看源代码,我们会看到两者都调用了一个被调用的函数range_include_internal,该函数对字符串参数有一个特殊情况,其行为与cover?. 后者调用rb_str_include_range_p具有更多特殊情况,包括您的数字情况。