Vérifier si une variable est définie?


581

Comment puis-je vérifier si une variable est définie dans Ruby? Existe-t-il une issetméthode de type disponible?

Réponses:


791

Utilisez le defined?mot - clé ( documentation ). Il renverra une chaîne avec le type de l'élément, ou nils'il n'existe pas.

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

Comme l'a souligné skalee: "Il convient de noter que la variable définie sur zéro est initialisée."

>> n = nil  
>> defined? n
 => "local-variable"

92
Il convient de noter que la variable qui est définie sur nil est initialisée.
skalee

7
Si vous souhaitez définir une variable si elle n'existe pas et la laisser seule si c'est le cas, voir la réponse de @ danmayer (impliquant l' ||=opérateur) ci-dessous.
jrdioko

2
Voici une autre bizarrerie dans laquelle je peux entrer. Si vous définissez une variable dans un bloc if pour lequel la condition n'est jamais remplie, defined?renvoie toujours vrai pour une variable définie dans ce bloc!
elsurudo

1
Existe-t-il une méthode comme defined?celle -là qui retourne booléen?
stevec

Pour retourner vrai / faux,!!defined?(object_name)
stevec

91

Ceci est utile si vous ne voulez rien faire s'il existe mais le créer s'il n'existe pas.

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

Cela ne crée la nouvelle instance qu'une seule fois. Après cela, il continue de renvoyer la var.


9
C'est un Ruby très idiomatique aussi et très typique, soit dit en passant.
jrdioko

38
Ne l'utilisez pas ||=avec des valeurs booléennes, de peur de ressentir la douleur de la confusion.
Andrew Marshall

6
avec ce que @AndrewMarshall a dit, évitez cet idiome avec tout ce qui pourrait également revenir nilà moins que vous ne vouliez vraiment évaluer l'expression chaque fois qu'elle est appelée quand elle revientnil
nzifnab

1
Si vous êtes travaillez avec booléens, et que vous voulez la valeur par défaut est vrai si la variable n'a pas été explicitement définie sur false, vous pouvez utiliser cette construction: var = (var or var.nil?)
Tony Zito

1
@ArnaudMeuret En quelque sorte , pas vraiment. - même si cela ne semble pas identique, cela vaut la peine de lire les réponses à cette question.
Fund Monica's Lawsuit

70

La syntaxe correcte pour l'instruction ci-dessus est:

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

en remplaçant ( var) par votre variable. Cette syntaxe renverra une valeur vraie / fausse pour évaluation dans l'instruction if.


11
Ce n'est pas nécessaire car nul est évalué à faux lorsqu'il est utilisé dans un test
Jerome

Pourquoi ne pas defined?(var) == nil?
vol7ron

@ vol7ron - C'est une syntaxe parfaitement valide. L'utilisation de l'appel à .nil?est plus idiomatique, comme on dit. Il est plus "orienté objet" de demander à un objet s'il l'est plutôt nilque d'utiliser un opérateur de comparaison. Aucun n'est difficile à lire, alors utilisez celui qui vous aide à expédier plus de produits.
juanpaco

À quelle déclaration faites-vous référence?!? N'utilisez pas une réponse comme commentaire à autre chose.
Arnaud Meuret

18

defined?(your_var)marchera. Selon ce que vous faites, vous pouvez également faire quelque chose commeyour_var.nil?


+1 your_var.nil?car il renvoie vrai ou faux et est beaucoup plus agréable à lire et à écrire que defined? var. Merci pour cela.
kakubei

28
your_var.nil?entraînera une erreur: undefined local variable or method your_varlorsqu'il n'est pas défini avant ...
Gobol

16

Essayez "à moins que" au lieu 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'est-ce que cette réponse ajoute qui n'a pas été dit par les autres réponses?
Andrew Grimm

2
Cela répond très bien à la question d'une manière plus utile, n'est-ce pas?
regardez

2
Le guide du style rubis dit "Favorisez à moins que ce ne soit fini si pour des conditions négatives" github.com/bbatsov/ruby-style-guide
ChrisPhoenix

9

Utilisez defined? YourVariable
Keep it simple idiot ..;)


8

Voici du code, rien de sorcier mais ça marche assez 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

De toute évidence, le code de coloration n'est pas nécessaire, juste une belle visualisation dans cet exemple de jouet.


Vraisemblablement parce que le nil?est facultatif.
James

8

AVERTISSEMENT concernant un motif de rubis commun

C'est la réponse clé: la defined?méthode. La réponse acceptée ci-dessus illustre parfaitement cela.

Mais il y a un requin qui se cache sous les vagues ...

Considérez ce type de motif rubis commun:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2revient toujours nil. La première fois que vous appelez method1, la @xvariable n'est pas définie - elle method2sera donc exécutée. et method2se mettra @xà nil. C'est bien, et tout va bien. Mais que se passe-t-il la deuxième fois que vous appelez method1?

N'oubliez pas que @x a déjà été défini sur zéro. But method2sera toujours exécuté à nouveau !! Si la méthode 2 est une entreprise coûteuse, ce n'est peut-être pas quelque chose que vous souhaitez.

Laissez la defined?méthode venir à la rescousse - avec cette solution, ce cas particulier est traité - utilisez ce qui suit:

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

Le diable est dans les détails: mais vous pouvez échapper à ce requin qui se cache avec la defined?méthode.


Vous avez tout à fait raison, merci d'avoir souligné cette mise en garde spécifique
Kulgar

5

Tu peux essayer:

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

Parce qu'il renvoie un booléen.


SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
Andrew Grimm

utiliser une unlessdéclaration semble trop compliqué
johannes

5

Comme de nombreux autres exemples le montrent, vous n'avez pas réellement besoin d'un booléen à partir d'une méthode pour faire des choix logiques en rubis. Ce serait une mauvaise forme de tout contraindre à un booléen, sauf si vous avez réellement besoin d'un booléen.

Mais si vous avez absolument besoin d'un booléen. Utilisation !! (bang bang) ou "falsy falsy révèle la vérité".

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

Pourquoi il n'est généralement pas avantageux de contraindre:

>> (!!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

Voici un exemple où cela est important car il repose sur la contrainte implicite de la valeur booléenne à sa représentation sous forme de chaîne.

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

3

Il convient de mentionner que l’utilisation de defined pour vérifier si un champ spécifique est défini dans un hachage peut se comporter de manière inattendue:

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

La syntaxe est correcte ici, mais defined? var['unknown'] sera évaluée dans la chaîne "method", donc le ifbloc sera exécuté

edit: La notation correcte pour vérifier si une clé existe dans un hachage serait:

if var.key?('unknown')

2

Veuillez noter la distinction entre "défini" et "attribué".

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

x est défini même s'il n'est jamais attribué!


C'est quelque chose que je viens de découvrir. Je m'attendais NameError Exception: undefined local variable or methodet j'étais confus quand la seule affectation / mention de la variable était dans un bloc if qui n'était pas touché.
Paul Pettengill

0

En outre, vous pouvez vérifier s'il est défini dans une chaîne via une interpolation, si vous codez:

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

Le système vous indiquera le type s'il est défini. S'il n'est pas défini, il renverra simplement un avertissement indiquant que la variable n'est pas initialisée.

J'espère que cela t'aides! :)


0

defined?est génial, mais si vous êtes dans un environnement Rails, vous pouvez également l'utiliser try, en particulier dans les cas où vous souhaitez vérifier un nom de variable dynamique:

foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo)        # => 1
try(:bar)        # => nil
try(my_foo)      # => 1
try(my_bar)      # => nil
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.