the - Mejor frase de ruby para "cero o cero"
the strategy design pattern (19)
Corto y claro
[0, nil].include?(val)
Estoy buscando una forma concisa para verificar un valor para ver si es nulo o cero. Actualmente estoy haciendo algo como:
if (!val || val == 0)
# Is nil or zero
end
Pero esto parece muy torpe.
Creo que tu 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, lo que en Ruby es nil
y false
.
Lo mejor que se me ocurre en este momento es
if val == nil || val == 0
# do stuff
end
Lo cual por supuesto no es muy inteligente, pero (muy) claro.
Desde Ruby 2.3.0 en adelante, puede combinar el operador de navegación segura ( &.
) Con Numeric#nonzero?
. &.
devuelve nil
si la instancia era nil
y nonzero?
- si el número era 0
:
unless val&.nonzero?
# Is nil or zero
end
O postfix:
do_something unless val&.nonzero?
En lugar de parchear mono en una clase, puedes usar refinamientos comenzando en 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 excesivo si quiere hacer este control una vez, pero si se repite a sí mismo es una 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
Los refinamientos se modificaron en el último minuto para ubicarlos en el archivo. Así que los ejemplos anteriores pueden haber demostrado esto, lo cual no funcionará.
class Car
using NilOrZero
end
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 de código que indica un defecto potencial 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.
Puede 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.
Esto es muy conciso
if (val || 0) == 0
# Is nil, false, or zero.
end
Funciona siempre y cuando no te importe tratar lo false
la misma manera que nil
. En los proyectos en los que he trabajado, esa distinción solo importa de vez en cuando. El resto del tiempo yo personalmente prefiero saltear .nil?
y tiene un código ligeramente más corto.
[ Actualización : ya no escribo este tipo de cosas. Funciona, pero es demasiado críptico. Intenté corregir mis errores cambiando los pocos lugares donde lo hice.]
Por cierto, no .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.
Esto se evalúa como verdadero para cero y cero: nil.to_s.to_d == 0
La forma más corta y mejor debería ser
if val&.>(0)
# do something
end
Para val&.>(0)
devuelve nil cuando val es nil ya que> básicamente es también un método, nil igual a false en ruby. Devuelve falso cuando val == 0
.
Me ocupo de esto al definir 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.
Otra solución:
if val.to_i == 0
# do stuff
end
Para ser lo más idiomático posible, sugeriría esto.
if val.nil? or val == 0
# Do something
end
Porque:
- Utiliza el nil? 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.
Puede usar case
si lo desea:
case val with nil, 0
# do stuff
end
Entonces puedes usar cualquier cosa que funcione con ===
, lo que a veces es bueno. O haz 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 un buen OOP, pero es muy flexible y funciona. Mi if
usualmente termina como case
todos modos.
Por supuesto Enum.any?
/ Enum.include?
también funciona ... si te gusta ser críptico:
if [0, nil].include? val
#do stuff
end
Lo correcto es, por supuesto, 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.
Puedes 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 se recomienda ya que los cambios en Objeto son difíciles de rastrear para los compañeros de trabajo y pueden hacer que su código sea impredecible para otros.
Rails lo hace 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 parte de detractores. http://www.joegrossberg.com/archives/002995.html
Realmente me gusta Rails en blank?
método para ese tipo de cosas, pero no regresará true
para 0
. Entonces puedes agregar tu método:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
Y comprobará si algún valor es nulo o 0:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
Si realmente te gustan los nombres de métodos con signos de interrogación al final:
if val.nil? || val.zero?
# do stuff
end
Su solución está bien, al igual que algunas de las otras soluciones.
Ruby puede hacerte buscar una forma bonita de hacer todo, si no tienes cuidado.
nil.to_i devuelve cero, así que a menudo hago esto:
val.to_i.zero?
Sin embargo, obtendrá una excepción si val alguna vez es un objeto que no responde a # a_i.
val ||= 0
if val == 0
# do something here
end