2008-10-16 5 views
63

Estoy buscando una forma concisa de verificar un valor para ver si es nulo o cero. Actualmente estoy haciendo algo como:Mejor expresión de ruby ​​para "cero o cero"

if (!val || val == 0) 
    # Is nil or zero 
end 

Pero esto parece muy torpe.

+1

lo que debería suceder si val es igual a 'false'? –

Respuesta

61

Los objetos tienen un nil? method.

if val.nil? || val == 0 
    [do something] 
end 

O, para una sola instrucción:

[do something] if val.nil? || val == 0 
+5

tenga cuidado con el uso de "o" y "y", por cierto, tienen una precedencia diferente y muy baja comparado con || y &&. Ver http: //blog.jayfields.com/2007/08/ruby-operator-precedence-of-and-which.html para algunas observaciones. –

+0

Estoy de acuerdo con un póster del "olor" en la pregunta, sin embargo, para mí esto es más de la manera ruby. – Jonke

+6

La precedencia de 'o' no requiere paréntesis aquí, y se leerá con total naturalidad a un Rubyista experimentado. Las únicas personas que son mordidas por '||' contra 'o' son personas que nunca han programado Perl :) – ephemient

4

Creo que su código es incorrecto; de hecho, probará tres valores: nil, false, y cero. Esto se debe a que la expresión !val es verdadera para todos los valores que son falsos, que en Ruby es nil y false.

Lo mejor que puedo llegar a este momento es

if val == nil || val == 0 
    # do stuff 
end 

que por supuesto no es muy inteligente, pero (muy) clara.

+0

probablemente pueda suponer que la variable en cuestión es numérica. Si ni siquiera sabe si es un Booleano o un Numérico, hay problemas mayores en el código. –

+0

Yo usaría .nil? not == nil – RichH

29

En primer lugar, creo que es la forma más concisa en la que puede verificar esa condición en particular.

En segundo lugar, para mí este es un olor a código que indica un posible defecto en su diseño. En general, cero y cero no deberían significar lo mismo. Si es posible, debe intentar eliminar la posibilidad de que val sea nulo antes de presionar este código, ya sea verificándolo al comienzo del método o mediante algún otro mecanismo.

Es posible que tenga una razón perfectamente legítima para hacerlo, en cuyo caso creo que su código es bueno, pero al menos consideraría tratar de deshacerse de la comprobación nula si es posible.

+4

¡Muy correcto sobre el olor del código! +1 Podría considerar buscar en el patrón NullObject http://en.wikipedia.org/wiki/Null_Object_pattern – abyx

9

Puede usar Object.nil? para probar nulo específicamente (y no quedar atrapado entre falso y nulo). También puedes aplicar un parche a un método en Objeto.

class Object 
    def nil_or_zero? 
    return (self.nil? or self == 0) 
    end 
end 

my_object = MyClass.new 
my_object.nil_or_zero? 
==> false 

esto no es recomendable ya que los cambios de objeto son difíciles para los compañeros de trabajo para rastrear, y puede hacer que el código impredecible a otros.

+0

Me gustaría modificar la clase numérica en lugar de Object. – epochwolf

+6

epochwolf, si pones esto en la clase Numérica, ¿'nil?' Siempre devolverá falso. 'nil?' solo devuelve verdadero en NilClass. –

+0

Puede implementar el método en 'Object',' NilClass' y 'Numeric'. 'Object' devolvería' false', 'NilClass' devolvería' true' y 'Numeric' devolvería' zero? '. – Stefan

2

Rails hace esto a través de métodos de consulta de atributos, donde además de falso y nulo, 0 y "" también evalúan a falso.

if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation 

Sin embargo, tiene su cuota de detractores. http://www.joegrossberg.com/archives/002995.html

+0

El enlace no funciona. Tengo curiosidad sobre el método '# attribute', porque no puedo encontrar nada de eso. – mrzasa

+0

Es algo que Rails/ActiveRecord agrega sobre la marcha. Si el cliente tiene un campo de nombre, ¿nombre? se agrega automáticamente para verificar si el nombre está en blanco o nulo. Consulte http://api.rubyonrails.org/classes/ActiveRecord/Base.html - busque la sección 'métodos de consulta de atributos' – Gishu

0

me encargo de esto mediante la definición de un "es?" método, que luego puedo implementar de manera diferente en varias clases. Entonces para Array, "¿es?" significa "tamaño> 0"; para Fixnum significa "self! = 0"; para String significa "self! = ''". NilClass, por supuesto, define "¿es?" simplemente devolviendo nil.

2

Para ser lo más idiomático posible, sugeriría esto.

if val.nil? or val == 0 
    # Do something 
end 

Porque:

  • Utiliza el nulo? método.
  • Utiliza el operador "or", que es preferible a ||.
  • No usa paréntesis, que no son necesarios en este caso. Los paréntesis solo deben usarse cuando sirven para algún propósito, como anular la precedencia de ciertos operadores.
+0

Aunque sé que esto es literalmente hace 7 años, he votado negativamente debido a esto: https://github.com/bbatsov/ruby-style-guide#no-and-or-or –

-3
val ||= 0 
if val == 0 
# do something here 
end 
+3

-1: ¿Qué pasa si el valor en 'val' necesita ser guardado? Está destruyendo los datos de entrada con este método, y existen formas mejores y menos destructivas de verificar cero o cero. –

+2

¿Qué tal if (val || 0) .zero? – timkay

30

Si realmente te gusta nombres de los métodos con los signos de interrogación al final:

 

if val.nil? || val.zero? 
    # do stuff 
end 
 

Su solución está muy bien, al igual que algunas de las otras soluciones.

Ruby puede hacer que busques una forma bonita de hacer todo, si no tienes cuidado.

0

Puede utilizar case si te gusta:

case val with nil, 0 
     # do stuff 
end 

continuación, puede utilizar cualquier cosa que funcione con ===, que es agradable a veces. O haga algo como esto:

not_valid = nil, 0 
case val1 with *not_valid 
     # do stuff 
end 
#do other stuff 
case val2 with *not_valid, false #Test for values that is nil, 0 or false 
     # do other other stuff 
end 

No es exactamente bueno OOP, pero es muy flexible y funciona. Mi if s generalmente termina como case s de todos modos.

Por supuesto Enum.any?/Enum.include? tipo de trabajos también ... si se quiere conseguir realmente críptico:

if [0, nil].include? val 
    #do stuff 
end 

Lo que hay que hacer es, por supuesto, para definir un método o función. O bien, si tiene que hacer lo mismo con muchos valores, use una combinación de esos simpáticos iteradores.

-2

Otra solución:

if val.to_i == 0 
    # do stuff 
end 
+1

Esto solo funciona si val es un entero o nulo; 0.5.to_i == 0, any_string.to_i == 0, etc. –

+0

'" 5 ".to_i == 5', pero está más o menos en lo cierto. Inteligente pero en realidad no funciona. –

5

nil.to_i devuelve cero, así que a menudo hago esto:

val.to_i.zero? 

Sin embargo, obtendrá una excepción si val es siempre un objeto que no hace respond_to #to_i.

+1

-1 por la misma razón que la respuesta de Scott no funciona. –

0

Me gusta mucho el método Rails blank? para ese tipo de cosas, pero no devolverá true para 0. Así que usted puede añadir su método:

def nil_zero? 
    if respond_to?(:zero?) 
    zero? 
    else 
    !self 
    end 
end 

y va a comprobar si un valor es nulo o 0:

nil.nil_zero? 
=> true 
0.nil_zero? 
=> true 
10.nil_zero? 
=> false 

if val.nil_zero? 
    #... 
end 
-1

Esto es muy concisa:

if (val || 0) == 0 
    # Is nil, false, or zero. 
end 

Funciona siempre y cuando no le importa tratar false lo mismo que nil. En los proyectos en los que he trabajado, esa distinción solo importa de vez en cuando. El resto del tiempo, personalmente prefiero omitir .nil? y tener un código ligeramente más corto.

[Actualización: Ya no escribo este tipo de cosas.Funciona, pero es demasiado críptico. He intentado corregir mis fechorías cambiando los pocos lugares donde lo hice.]

Por cierto, no usé .zero? ya que esto genera una excepción si val es, por ejemplo, una cadena. Pero .zero? estaría bien si sabes que no es el caso.

+0

'[editado]' Pensé que si 'val' era nil, entonces esta expresión se evaluaría como' nil == 0' (y, por lo tanto, devolvería 'false'). Sin embargo, parece que realmente funciona, aunque no creo que sea muy legible. – omnikron

+0

Ahora creo que mi enfoque aquí fue demasiado críptico, solo para guardar unos pocos caracteres, y no lo escribiría así hoy en día. Así que no espero ningún voto positivo, pero estoy un poco sorprendido por los votos a favor de una respuesta que funciona (aunque era de dudoso gusto) ... – antinome

0

En lugar de mono parchear una clase, you could use refinements a partir de Ruby 2.1. Los refinamientos son similares a los parches de mono; en eso, le permiten modificar la clase, pero la modificación se limita al ámbito en el que desea usarla.

Esto es exagerado si desea hacer este control una vez, pero si se repite usted mismo es gran alternativa al parche de monos.

module NilOrZero 
    refine Object do 
    def nil_or_zero? 
     nil? or zero? 
    end 
    end 
end 

using NilOrZero 
class Car 
    def initialize(speed: 100) 
    puts speed.nil_or_zero? 
    end 
end 

car = Car.new    # false 
car = Car.new(speed: nil) # true 
car = Car.new(speed: 0) # true 

Refinements were changed en el último minuto para estar en el ámbito en el fichero. Así que los ejemplos anteriores pueden haber demostrado esto, lo cual no funcionará.

class Car 
    using NilOrZero 
end 
10

De Rubí 2.3.0 en adelante, se puede combinar el operador navegación segura (&.) con Numeric#nonzero?. &. vuelve nil si la instancia fue nil y nonzero? - si el número era 0:

unless val&.nonzero? 
    # Is nil or zero 
end 

O postfijos:

do_something unless val&.nonzero? 
+0

Esta fue una excelente respuesta nueva y moderna. Además, hay un excelente artículo sobre por qué usarlo aquí: [The Safe Navigation Operator (&.) En Ruby] (http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/) –

+0

Muy conciso, pero sin el comentario me llevaría un momento entender que 'a menos que val & .nonzero?' Se traduzca a "si val es nulo o cero" – Stefan

+1

@Stefan, de acuerdo. Yo no usaría esto en el código de producción yo mismo. Lo incluí para completar el proceso. Sin embargo, lo opuesto es perfectamente legible: 'do_something if val & .nonzero?' (También conocido como 'val' no es 'nil' y no es cero). – ndn

1

corto y claro

[0, nil].include?(val)

+0

También puede revertir eso: 'val.in? [0, nil] ' – mahemoff

2

más cortos y mejor manera debe ser

if val&.>(0) 
    # do something 
end 

Para val&.>(0) devuelve nil cuando val es nulo puesto> básicamente es también un método, nada igual a falsa en rubí. Devuelve falso cuando val == 0.

+0

¿El más corto sobre qué ?, ¿la mejor manera que qué? –

0

Este resultado verdadero de cero y cero: nil.to_s.to_d == 0