为什么字符串'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具有更多特殊情况,包括您的数字情况。