Verifica se una variabile è definita?


581

Come posso verificare se una variabile è definita in Ruby? È disponibile un issetmetodo di tipo?

Risposte:


791

Usa la defined?parola chiave ( documentazione ). Restituirà una stringa con il tipo di elemento, o nilse non esiste.

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

Come ha commentato skalee: "Vale la pena notare che la variabile impostata su zero è inizializzata".

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

92
Vale la pena notare che la variabile impostata su nil è inizializzata.
skalee,

7
Se vuoi impostare una variabile se non esiste e lasciarla sola se lo fa, vedi la risposta di @ danmayer (che coinvolge l' ||=operatore) di seguito.
jrdioko,

2
Ecco un'altra stranezza che posso considerare. Se definisci una variabile in un blocco if per cui la condizione non viene mai soddisfatta, defined?restituisce comunque vero per una variabile definita all'interno di quel blocco!
elsurudo,

1
Esiste un metodo del genere defined?che ritorna booleano?
Stevec,

Per restituire vero / falso,!!defined?(object_name)
stevec il

91

Questo è utile se non vuoi fare nulla se esiste ma crealo se non esiste.

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

Questo crea la nuova istanza solo una volta. Dopodiché continua a restituire il var.


9
Questo è anche Ruby molto idiomatico e molto tipico, tra l'altro.
jrdioko,

38
Basta non usare ||=valori booleani, per non sentire il dolore della confusione.
Andrew Marshall,

6
insieme a ciò che ha detto @AndrewMarshall, evita questo idioma con tutto ciò che potrebbe anche tornare, nila meno che tu non voglia davvero valutare l'espressione ogni volta che viene chiamato quando ritornanil
nzifnab

1
Se si sta lavorando con booleani, e desidera che il valore predefinito per essere vero se la variabile non è stato esplicitamente impostato su false, è possibile utilizzare questa costruzione: var = (var or var.nil?)
Tony Zito

1
@ArnaudMeuret In un certo senso , non proprio. - anche se potrebbe non sembrare identico, vale la pena leggere le risposte a questa domanda.
Fondi Monica's Lawsuit

70

La sintassi corretta per l'istruzione precedente è:

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

sostituendo ( var) con la tua variabile. Questa sintassi restituirà un valore vero / falso per la valutazione nell'istruzione if.


11
Ciò non è necessario poiché zero viene valutato come falso quando utilizzato in un test
Jerome

Perché no defined?(var) == nil?
vol7ron,

@ vol7ron - Questa è una sintassi perfettamente valida. L'uso della chiamata a .nil?è più idiomatico, come si suol dire. È più "orientato agli oggetti" chiedere a un oggetto se non nilusare un operatore di confronto. Nessuno dei due è difficile da leggere, quindi usa quello che ti aiuta a spedire più prodotti.
Juanpaco,

A quale affermazione ti riferisci?!? Non usare una risposta come commento a qualcos'altro.
Arnaud Meuret,

18

defined?(your_var)funzionerà. A seconda di cosa stai facendo, puoi anche fare qualcosa del genereyour_var.nil?


+1 your_var.nil?perché restituisce vero falso ed è molto più bello da leggere e da scrivere di defined? var. Grazie per questo.
kakubei,

28
your_var.nil?comporterà un errore: undefined local variable or method your_varquando non definito prima ...
Gobol

16

Prova "a meno" invece di "if"

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

Cosa aggiunge questa risposta che non è stata detta dalle altre risposte?
Andrew Grimm,

2
Risponde molto bene alla domanda in un modo più utile, no?
guarda il

2
La guida allo stile ruby ​​dice "Favorisci se non in caso di condizioni negative" github.com/bbatsov/ruby-style-guide
ChrisPhoenix


8

Ecco del codice, niente scienza missilistica ma funziona abbastanza bene

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

Chiaramente, il codice da colorare non è necessario, solo una bella visualizzazione in questo esempio di giocattolo.


Presumibilmente perché nil?è facoltativo.
James,

8

ATTENZIONE: un modello Ruby comune

Questa è la risposta chiave: il defined?metodo. La risposta accettata sopra illustra questo perfettamente.

Ma c'è uno squalo, in agguato sotto le onde ...

Considera questo tipo di modello rubino comune:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2ritorna sempre nil. La prima volta che chiami method1, la @xvariabile non è impostata, quindi method2verrà eseguita. e method2verrà impostato @xsu nil. Va bene, e tutto bene e bene. Ma cosa succede la seconda volta che chiami method1?

Ricorda che @x è già stato impostato su zero. But method2sarà ancora eseguito di nuovo !! Se method2 è un'impresa costosa, potrebbe non essere qualcosa che desideri.

Lascia che il defined?metodo venga in soccorso - con questa soluzione, viene gestito quel caso particolare - utilizza quanto segue:

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

Il diavolo è nei dettagli: ma puoi eludere lo squalo in agguato con il defined?metodo.


Hai perfettamente ragione, grazie per aver messo in evidenza questo avvertimento specifico
Kulgar

5

Puoi provare:

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

Perché restituisce un valore booleano.


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

usare unlessun'affermazione sembra eccessivamente complicato
johannes,

5

Come molti altri esempi mostrano che in realtà non è necessario un valore booleano da un metodo per effettuare scelte logiche in ruby. Sarebbe una forma scadente costringere tutto a un valore booleano a meno che tu non abbia effettivamente bisogno di un booleano.

Ma se hai assolutamente bisogno di un booleano. Uso !! (bang bang) o "falsy falsy rivela la verità".

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

Perché di solito non paga per forzare:

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

Ecco un esempio in cui è importante perché si basa sulla coercizione implicita del valore booleano sulla sua rappresentazione di stringa.

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

3

Va notato che l'utilizzo definedper verificare se un campo specifico è impostato in un hash potrebbe comportarsi in modo imprevisto:

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

La sintassi è corretta qui, ma defined? var['unknown']verrà valutata sulla stringa "method", quindi ilif blocco verrà eseguito

modifica: la notazione corretta per verificare se esiste una chiave in un hash sarebbe:

if var.key?('unknown')

2

Si noti la distinzione tra "definito" e "assegnato".

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

x è definito anche se non è mai assegnato!


Questo è qualcosa che ho appena incontrato. Mi aspettavo NameError Exception: undefined local variable or methoded ero confuso quando l'unica assegnazione / menzione della variabile era in un blocco if che non veniva colpito.
Paul Pettengill,

0

Inoltre, puoi verificare se è definito mentre sei in una stringa tramite interpolazione, se codifichi:

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

Il sistema ti dirà il tipo se è definito. Se non è definito, restituirà solo un avviso indicante che la variabile non è inizializzata.

Spero che sia di aiuto! :)


0

defined?è fantastico, ma se ti trovi in ​​un ambiente Rails puoi anche usarlo try, specialmente nei casi in cui desideri controllare un nome di variabile dinamico:

foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo)        # => 1
try(:bar)        # => nil
try(my_foo)      # => 1
try(my_bar)      # => nil
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.