2011-06-17 15 views
13

¿Cuál es la ciencia detrás del hecho de que el método to_i en las instancias Ruby's NilClass devuelve cero? Devolver nil o plantear una excepción no sería más lógico?Ruby Nil and Zero

+3

relacionadas: Usted puede usar 'n = entero (str)' si desea lanzar una excepción en caso de fallo. – Dogbert

Respuesta

12

NilClass define #to_i por la misma razón que define un #to_a que devuelve []. Te está dando algo del tipo correcto, sino una especie de vacío valor.

Esto es bastante útil. Por ejemplo:

<%= big.long.expr.nil? ? "" : big.long.expr %> 

se convierte en:

<%= big.long.expr %> 

Mucho mejor! (Erb está llamando #to_s que, por nula, es "".) Y:

if how.now.brown.cow && how.now.brown.cow[0] 
    how.now.brown.cow[0] 
else 
    0 
end 

se convierte en:

how.now.brown.cow.to_a[0].to_i 

Las conversiones cortos existen cuando se necesita sólo una representación. Las conversiones largas son las que los métodos centrales de Ruby llaman y requieren algo muy cercano. Úselos si quiere una verificación de tipo.

Eso es:

thing.to_int # only works when almost Integer already. NilClass throws NoMethodError 

thing.to_i # this works for anything that cares to define a conversion 
+0

* "¡Mucho mejor!" * Sí, eso depende de cuán bien tú y cualquier otra persona que trabaje en el proyecto conozcan a Ruby y cuánto quieras confiar en un comportamiento poco intuitivo. 'nil.to_i' devolver 0 en lugar de generar una excepción no tiene mucho sentido lógicamente. ¿Cómo se puede obtener '0' de' nil'? No es como 'nil == 0' devuelve verdadero tampoco, pero' to_i' implica una equivalencia. –

+4

@Ed S .: No, 'to_int' implica una equivalencia,' to_i' es tan laxo, realmente no implica mucho de nada. –

+1

¡excelente respuesta! Siempre pasé por alto las largas conversiones, ahora puedo entenderlas y cómo se ajustan a la filosofía del rubí. –

13

se ajusta a la filosofía de la permisividad Rubí (a diferencia de, por ejemplo, el rigor de Python):

nil.to_i #=> 0 
"".to_i #=> 0 
"123hello".to_i #=> 123 
"hello".to_i #=> 0 

Para ser honesto, creo que esto es excesivamente permisiva. Como señaló Zabba, puede usar Kernel#Integer(string) para una conversión estricta.

+3

No necesita usar expresiones regulares. Si desea errores cuando una cadena no es un número completo (como "123hello"), puede hacerlo así: 'Integer (" 123hello ")' (arroja un 'ArgumentError'). – Zabba

+0

+1 sí, parece excesivamente permisivo. bien dicho. – Peter

6

to_i significa "convertirme a un entero si puede".

Si quieres "si eres muy parecida a un entero, dame tu valor entero, sino da un NoMethodError", luego usa .to_int.

Hay otra cuestión que se pregunta sobre la diferencia entre to_i y to_int, to_s frente to_str, etc. Avisadme si desea que encuentre por usted.

6

El protocolo de to_i dice que debe devolver un Integer y no debe lanzar una excepción. Ambas sugerencias violan al menos una de esas reglas. Entonces, no, esos no solo no serían más lógicos, serían simplemente inválidos.

Tenga en cuenta, sin embargo, que nilno responden a to_int. Si hizo responden a to_int, eso sería, de hecho, "ilógico".

+1

El hecho de que el protocolo diga que 'to_i' debe devolver un número entero no hace que este comportamiento sea lógico, simplemente lo hace conforme (dado que es mejor ser conformes aunque ilógico). –

1

Si usted sucede estar en rieles, puede utilizar try:

nil.to_i # => 0 
nil.try :to_i # => nil