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

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

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

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

 case '3'
 when ('0'...'9')
     puts "number is valid"
 else
   puts "number is not valid"
 end

输出: number is valid

 case '3'
 when ('0'...'9')
     puts "number is valid"
 else
   puts "number is not valid"
 end

输出: 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

回答

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

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

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

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

case 3 # or variable.to_i
when 0...10
  puts 'number is valid'
else
  puts 'number is invalid'
end

这是有效的,因为整数不是基于字符代码进行比较,而是基于实际值。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

  • @jockofcode The [case equality of a method](https://ruby-doc.org/core-3.0.1/Method.html#method-i-3D-3D-3D) calls the method with the case argument/input. So passing `range.method(:member?)` to *when* resolves it using `range.method(:member?) === input` -> `range.method(:member?).call(input)` whereas providing just `range` will result in `range === input` -> `range.cover?(input)`
  • @jockofcode In this specific scenario there is also the option to use `'0'..'9'` (two dots instead of three, see the [`Range`](https://ruby-doc.org/core-3.0.1/Range.html) documentation). But this only works if you expect a single digit. This is similar to the regex `[0-9]`.

回答

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

begin <= obj < end

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

'0' <= '3' < '10'

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

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


以上是为什么字符串'3'在范围为('0'…'10')的case语句中不匹配?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>