Cuando trato de hacer coincidir la cadena '3' en una declaración de caso, coincide si el rango sube a '9', pero no a '10'.
Supongo que tiene algo que ver con el operador triple igual, pero no sé la razón exacta por la que puede estar en el rango, pero no igualado.
Aquí hay una ejecución de IRB que documenta ambos casos que funcionan (con '9') y no funcionan (con '10'):
case '3' when ('0'...'9') puts "number is valid" else puts "number is not valid" end Salida: number is valid
case '3' when ('0'...'10') puts "number is valid" else puts "number is not valid" end Salida: number is not valid
Los métodos que utilicé como referencia para los resultados esperados son
Enumerable#include?
Enumerable#member?
y ver lo que se genera cuando se convierte en una matriz es ( Enumerable#to_a ).
El resultado del operador "igualdad de casos" ( === ) me sorprendió.
puts ('0'...'10').include?('3') # => true puts ('0'...'10').member?('3') # => true puts ('0'...'10') === '3' # => false puts ('0'...'10').to_a # => ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]=== dice que es equivalente a cover? , y la documentación de este último establece que es equivalente a
begin <= obj < endEntonces, en su caso, estamos obteniendo
'0' <= '3' < '10' Y <= y < en las cadenas se comparan usando el orden del diccionario, por lo que la comparación es falsa.
Por otro lado, tenemos que investigar un poco más para descubrir qué member? / include? realmente hacer (los dos son equivalentes). Si miramos en el código fuente, vemos que ambos invocan una función llamada range_include_internal que tiene un caso especial para argumentos de cadena que se comporta de manera diferente a cover? . Este último llama a rb_str_include_range_p que tiene aún más casos especiales, incluido su caso de dígitos.
Cobertura de uso de rangos cover? para la igualdad de casos . Por lo tanto, está comparando '3' >= '0' && '3' < '10' que da como resultado false porque '3' < '10' #=> false . Las cadenas se comparan en función de los valores de los caracteres.
Para una mejor comprensión, es posible que desee ver una cadena como una matriz de caracteres:
['3'] <=> ['1', '0'] #=> 1 (first operand is larger than the second)Para resolver el problema, convierta la entrada de su caso en un número entero y use rangos de números enteros:
case 3 # or variable.to_i when 0...10 puts 'number is valid' else puts 'number is invalid' end Esto funciona porque los números enteros no se comparan en función del código de caracteres, sino del valor real. 3 >= 0 && 3 < 10 da como resultado true .
Alternativamente, ¿podría decir explícitamente cuándo usar el member? (¿o include? ), al no pasar un rango, sino un método en su lugar.
case '3' when ('0'...'10').method(:member?) puts 'number is valid' else puts 'number is invalid' end