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