¿Verificando si una variable está definida?

581

¿Cómo puedo verificar si una variable está definida en Ruby? ¿Hay un issetmétodo de tipo disponible?

Solo lectura
fuente

Respuestas:

791

Use la defined?palabra clave ( documentación ). Devolverá una Cadena con el tipo de elemento, o nilsi no existe.

>> a = 1
 => 1
>> defined? a
 => "local-variable"
>> defined? b
 => nil
>> defined? nil
 => "nil"
>> defined? String
 => "constant"
>> defined? 1
 => "expression"

Como comentó skalee: "Vale la pena señalar que la variable que se establece en nulo se inicializa".

>> n = nil  
>> defined? n
 => "local-variable"
Ricardo Acras
fuente
92
Vale la pena señalar que la variable que se establece nil se inicializa.
skalee
77
Si desea establecer una variable si no existe y dejarla sola si es así, consulte la respuesta de @ danmayer (que involucra al ||=operador) a continuación.
jrdioko
2
Aquí hay otra rareza en la que puedo entrar ... Si define una variable en un bloque if para el que nunca se cumple la condición, ¡ defined?aún se devuelve verdadero para una variable definida dentro de ese bloque!
elsurudo
1
¿Hay un método como defined?ese devuelve boolean?
stevec
Para devolver verdadero / falso,!!defined?(object_name)
stevec 01 de
91

Esto es útil si no desea hacer nada si existe, sino crearlo si no existe.

def get_var
  @var ||= SomeClass.new()
end

Esto solo crea la nueva instancia una vez. Después de eso, simplemente sigue devolviendo la var.

danmayer
fuente
99
Este es Ruby muy idiota también y muy típico, por cierto.
jrdioko
38
Simplemente no lo use ||=con valores booleanos, para que no sienta el dolor de la confusión.
Andrew Marshall
66
junto con lo que dijo @AndrewMarshall, evitar este idioma con cualquier cosa que pueda volver nilasí a menos que realmente desea evaluar la expresión cada vez que se llama cuando se hace el retornonil
nzifnab
1
Si está trabajando con booleanos y desea que el valor predeterminado sea verdadero si la variable no se estableció explícitamente en falso, puede usar esta construcción: var = (var or var.nil?)
Tony Zito
1
@ArnaudMeuret Más o menos , en realidad no. - Si bien puede no parecer idéntico, vale la pena leer las respuestas a esa pregunta.
Financia la demanda de Mónica el
70

La sintaxis correcta para la declaración anterior es:

if (defined?(var)).nil? # will now return true or false
 print "var is not defined\n".color(:red)
else
 print "var is defined\n".color(:green)
end

sustituyendo ( var) con su variable. Esta sintaxis devolverá un valor verdadero / falso para la evaluación en la instrucción if.

Foomip
fuente
11
Eso no es necesario ya que nil se evalúa como falso cuando se usa en una prueba
Jerome el
¿Por qué no defined?(var) == nil?
vol7ron
@ vol7ron: esa es una sintaxis perfectamente válida. Usar la llamada a .nil?es más idiomático, como dicen. Es más "orientado a objetos" preguntarle a un objeto si es nilque usar un operador de comparación. Ninguno de los dos es difícil de leer, así que use el que le ayude a enviar más productos.
juanpaco
¿A qué afirmación te refieres? No use una respuesta como comentario para otra cosa.
Arnaud Meuret
18

defined?(your_var)trabajará. Dependiendo de lo que estés haciendo, también puedes hacer algo comoyour_var.nil?

digitalsanctum
fuente
+1 your_var.nil?porque devuelve verdadero de falso y es mucho más agradable de leer y escribir que defined? var. Gracias por esto.
kakubei
28
your_var.nil?producirá un error: undefined local variable or method your_varcuando no se haya definido antes ...
Gobol
16

Intente "a menos que" en lugar de "si"

a = "apple"
# Note that b is not declared
c = nil

unless defined? a
    puts "a is not defined"
end

unless defined? b
    puts "b is not defined"
end

unless defined? c
    puts "c is not defined"
end
usuario761856
fuente
¿Qué agrega esta respuesta que no han dicho las otras respuestas?
Andrew Grimm
2
Responde muy bien a la pregunta de una manera más útil, ¿no?
mira el
2
La guía de estilo rubí dice "Favor a menos que sea por condiciones negativas" github.com/bbatsov/ruby-style-guide
ChrisPhoenix
9

Use defined? YourVariable
Keep it simple tonly ..;)

Saqib R.
fuente
8

Aquí hay un código, nada de ciencia espacial pero funciona lo suficientemente bien

require 'rubygems'
require 'rainbow'
if defined?(var).nil?  # .nil? is optional but might make for clearer intent.
 print "var is not defined\n".color(:red)
else
 print "car is defined\n".color(:green)
end

Claramente, el código de color no es necesario, solo una buena visualización en este ejemplo de juguete.

Sardathrion - contra el abuso SE
fuente
Presumiblemente porque el nil?es opcional.
James
8

ADVERTENCIA Re: Un patrón de rubí común

Esta es la respuesta clave: el defined?método. La respuesta aceptada arriba ilustra esto perfectamente.

Pero hay un tiburón al acecho debajo de las olas ...

Considere este tipo de patrón de rubí común:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2siempre vuelve nil. La primera vez que llama method1, la @xvariable no está establecida, por method2lo tanto , se ejecutará. y method2se establecerá @xen nil. Eso está bien, y todo bien y bien. ¿Pero qué pasa la segunda vez que llamas method1?

Recuerde que @x ya se ha establecido en nulo. But method2todavía se ejecutará de nuevo !! Si method2 es una tarea costosa, esto podría no ser algo que desee.

Deje que el defined?método salga al rescate - con esta solución, se maneja ese caso particular - use lo siguiente:

  def method1
    return @x if defined? @x
    @x = method2
  end

El diablo está en los detalles: pero puedes evadir a ese tiburón al acecho con el defined?método.

BKSpurgeon
fuente
Tiene toda la razón, gracias por resaltar esa advertencia específica
Kulgar
5

Puedes probar:

unless defined?(var)
  #ruby code goes here
end
=> true

Porque devuelve un valor booleano.

Bruno Barros
fuente
SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
Andrew Grimm
usar una unlessdeclaración parece demasiado complicado
johannes
5

Como muchos otros ejemplos muestran, en realidad no necesita un booleano de un método para tomar decisiones lógicas en ruby. Sería una forma deficiente obligar todo a un booleano a menos que realmente necesite un booleano.

Pero si absolutamente necesitas un booleano. Utilizar !! (bang bang) o "falso falso revela la verdad".

 irb
>> a = nil
=> nil
>> defined?(a)
=> "local-variable"
>> defined?(b)
=> nil
>> !!defined?(a)
=> true
>> !!defined?(b)
=> false

Por qué no suele pagar coaccionar:

>> (!!defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red)) == (defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red))
=> true

Aquí hay un ejemplo donde importa porque se basa en la coerción implícita del valor booleano a su representación de cadena.

>> puts "var is defined? #{!!defined?(a)} vs #{defined?(a)}"
var is defined? true vs local-variable
=> nil
donnoman
fuente
3

Cabe mencionar que usar definedpara verificar si un campo específico está configurado en un hash podría comportarse de manera inesperada:

var = {}
if defined? var['unknown']
  puts 'this is unexpected'
end
# will output "this is unexpected"

La sintaxis es correcta aquí, pero defined? var['unknown']se evaluará en la cadena "method", por lo queif que se ejecutará bloque

editar: La notación correcta para verificar si existe una clave en un hash sería:

if var.key?('unknown')
Leberknecht
fuente
2

Tenga en cuenta la distinción entre "definido" y "asignado".

$ ruby -e 'def f; if 1>2; x=99; end;p x, defined? x; end;f'
nil
"local-variable"

¡x se define aunque nunca se asigne!

Robert Klemme
fuente
Esto es algo que acabo de encontrar. Estaba esperando NameError Exception: undefined local variable or method, y estaba confundido cuando la única asignación / mención de la variable estaba en un bloque if que no estaba siendo golpeado.
Paul Pettengill
0

Además, puede verificar si está definido mientras está en una cadena a través de la interpolación, si codifica:

puts "Is array1 defined and what type is it? #{defined?(@array1)}"

El sistema le dirá el tipo si está definido. Si no está definido, solo devolverá una advertencia diciendo que la variable no está inicializada.

¡Espero que esto ayude! :)

Elliott
fuente
0

defined?es genial, pero si está en un entorno Rails, también puede usarlo try, especialmente en los casos en que desea verificar un nombre de variable dinámica:

foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo)        # => 1
try(:bar)        # => nil
try(my_foo)      # => 1
try(my_bar)      # => nil
John Donner
fuente