¿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?

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"

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.


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.


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?


+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

¿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


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.


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.


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.


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

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')

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!


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! :)


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.