Prüfen, ob eine Variable definiert ist?

581

Wie kann ich überprüfen, ob in Ruby eine Variable definiert ist? Gibt es eine issetMethode vom Typ?

Schreibgeschützt
quelle

Antworten:

791

Verwenden Sie das defined?Schlüsselwort ( Dokumentation ). Es wird eine Zeichenfolge mit der Art des Elements zurückgegeben, oder nilwenn es nicht vorhanden ist.

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

Wie Skalee kommentierte: "Es ist erwähnenswert, dass die Variable, die auf Null gesetzt ist, initialisiert wird."

>> n = nil  
>> defined? n
 => "local-variable"
Ricardo Acras
quelle
92
Es ist erwähnenswert, dass die Variable, auf die gesetzt nil ist, initialisiert wird.
Skalee
7
Wenn Sie eine Variable festlegen möchten, wenn sie nicht vorhanden ist, und sie in Ruhe lassen möchten, lesen Sie die Antwort von @ danmayer (unter Einbeziehung des ||=Operators) weiter unten.
jrdioko
2
Hier ist eine weitere Kuriosität, auf die ich eingehen kann. Wenn Sie eine Variable in einem if-Block definieren, für die die Bedingung nie erfüllt ist, wird defined?für eine in diesem Block definierte Variable immer noch true zurückgegeben!
Elsurudo
1
Gibt es eine defined?solche Methode , die einen Booleschen Wert zurückgibt?
Stevec
Um wahr / falsch zurückzugeben,!!defined?(object_name)
stevec
91

Dies ist nützlich, wenn Sie nichts tun möchten, wenn es vorhanden ist, sondern es erstellen möchten, wenn es nicht vorhanden ist.

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

Dadurch wird die neue Instanz nur einmal erstellt. Danach wird die Var einfach weiter zurückgegeben.

danmayer
quelle
9
Dies ist auch sehr idiomatisch Ruby und übrigens sehr typisch.
Jrdioko
38
Verwenden ||=Sie es nur nicht mit booleschen Werten, damit Sie nicht den Schmerz der Verwirrung spüren.
Andrew Marshall
6
Vermeiden Sie zusammen mit dem, was @AndrewMarshall gesagt hat, diese Redewendung mit allem, was ebenfalls zurückkehren könnte, es nilsei denn, Sie möchten den Ausdruck wirklich jedes Mal bewerten, wenn er aufgerufen wird, wenn er zurückkehrtnil
nzifnab
1
Wenn Sie sind mit booleans zu arbeiten, und wollen , dass der Standardwert um wahr zu sein , wenn die Variable nicht explizit auf false gesetzt, können Sie diese Konstruktion verwenden: var = (var or var.nil?)
Tony Zito
1
@ArnaudMeuret Irgendwie nicht wirklich. - Auch wenn es nicht identisch zu sein scheint, lohnt es sich, die Antworten auf diese Frage zu lesen.
Fund Monica Klage
70

Die korrekte Syntax für die obige Anweisung lautet:

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

Ersetzen ( var) durch Ihre Variable. Diese Syntax gibt einen True / False-Wert zur Auswertung in der if-Anweisung zurück.

Foomip
quelle
11
Dies ist nicht erforderlich, da nil bei Verwendung in einem Test als falsch bewertet wird
Jerome
Warum nicht defined?(var) == nil?
Vol7ron
@ vol7ron - Das ist eine vollkommen gültige Syntax. Die Verwendung des Anrufs an .nil?ist idiomatischer, wie sie sagen. Es ist "objektorientierter", ein Objekt zu fragen, ob es nileinen Vergleichsoperator verwendet. Beides ist nicht schwer zu lesen. Verwenden Sie also dasjenige, mit dem Sie mehr Produkte versenden können.
Juanpaco
Auf welche Aussage beziehen Sie sich?!? Verwenden Sie eine Antwort nicht als Kommentar zu etwas anderem.
Arnaud Meuret
18

defined?(your_var)wird funktionieren. Je nachdem, was Sie tun, können Sie auch so etwas tunyour_var.nil?

digitalsanctum
quelle
+1, your_var.nil?weil es true oder false zurückgibt und viel besser zu lesen und zu schreiben ist als defined? var. Danke dafür.
Kakubei
28
your_var.nil?wird zu einem Fehler führen: undefined local variable or method your_varwenn nicht vorher definiert ...
Gobol
16

Versuchen Sie "es sei denn" anstelle von "wenn"

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
user761856
quelle
Was fügt diese Antwort hinzu, was von den anderen Antworten nicht gesagt wurde?
Andrew Grimm
2
Es beantwortet die Frage sehr gut auf eine weitere nützliche Weise, nicht wahr?
Schauen Sie
2
Der Ruby Style Guide sagt "Bevorzugung, wenn nicht für negative Bedingungen" github.com/bbatsov/ruby-style-guide
ChrisPhoenix
9

Verwenden defined? YourVariable
Sie es einfach albern ..;)

Saqib R.
quelle
8

Hier ist ein Code, nichts Raketenwissenschaft, aber es funktioniert gut genug

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

Der Farbcode ist natürlich nicht erforderlich, nur eine schöne Darstellung in diesem Spielzeugbeispiel.

Sardathrion - gegen SE-Missbrauch
quelle
Vermutlich, weil das nil?optional ist.
James
8

WARNUNG Betreff: Ein allgemeines Rubinmuster

Dies ist die Schlüsselantwort: die defined?Methode. Die oben akzeptierte Antwort veranschaulicht dies perfekt.

Aber da lauert ein Hai unter den Wellen ...

Betrachten Sie diese Art von häufigem Rubinmuster:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2kehrt immer zurück nil. Beim ersten Aufruf method1wird die @xVariable nicht gesetzt - daher method2wird sie ausgeführt. und method2wird eingestellt @xauf nil. Das ist in Ordnung und alles schön und gut. Aber was passiert beim zweiten Anruf method1?

Denken Sie daran, dass @x bereits auf Null gesetzt wurde. But method2wird noch wieder laufen !! Wenn Methode2 ein kostspieliges Unterfangen ist, ist dies möglicherweise nicht das, was Sie wollen.

Lassen Sie die defined?Methode zur Rettung kommen - mit dieser Lösung wird dieser spezielle Fall behandelt - verwenden Sie Folgendes:

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

Der Teufel steckt im Detail: Aber mit der defined?Methode können Sie diesem lauernden Hai ausweichen .

BKSpurgeon
quelle
Sie haben vollkommen recht, danke, dass Sie diese spezielle Einschränkung hervorgehoben haben
Kulgar,
5

Du kannst es versuchen:

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

Weil es einen Booleschen Wert zurückgibt.

Bruno Barros
quelle
SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
Andrew Grimm
eine unlessAussage zu verwenden scheint zu kompliziert
Johannes
5

Wie viele andere Beispiele zeigen, benötigen Sie keinen Booleschen Wert aus einer Methode, um logische Entscheidungen in Ruby zu treffen. Es wäre eine schlechte Form, alles zu einem Booleschen Wert zu zwingen, es sei denn, Sie benötigen tatsächlich einen Booleschen Wert.

Aber wenn Sie unbedingt einen Booleschen Wert brauchen. Verwenden !! (Bang Bang) oder "Falsy Falsy enthüllt die Wahrheit".

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

Warum es sich normalerweise nicht lohnt, zu zwingen:

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

Hier ist ein Beispiel, wo es wichtig ist, weil es auf dem impliziten Zwang des booleschen Werts zu seiner Zeichenfolgendarstellung beruht.

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

Es sollte erwähnt werden, dass sich die Verwendung definedzur Überprüfung, ob ein bestimmtes Feld in einem Hash festgelegt ist, möglicherweise unerwartet verhält:

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

Die Syntax ist hier korrekt, wird jedoch defined? var['unknown']als Zeichenfolge ausgewertet "method", sodass der ifBlock ausgeführt wird

Bearbeiten: Die korrekte Notation zum Überprüfen, ob ein Schlüssel in einem Hash vorhanden ist, lautet:

if var.key?('unknown')
leberknecht
quelle
2

Bitte beachten Sie die Unterscheidung zwischen "definiert" und "zugewiesen".

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

x wird definiert, obwohl es nie zugewiesen wird!

Robert Klemme
quelle
Das ist etwas, auf das ich gerade gestoßen bin. Ich hatte erwartet NameError Exception: undefined local variable or methodund war verwirrt, als die einzige Zuweisung / Erwähnung der Variablen in einem if-Block war, der nicht getroffen wurde.
Paul Pettengill
0

Sie können auch überprüfen, ob es in einer Zeichenfolge durch Interpolation definiert ist, wenn Sie Folgendes codieren:

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

Das System teilt Ihnen den Typ mit, wenn er definiert ist. Wenn es nicht definiert ist, wird nur eine Warnung zurückgegeben, die besagt, dass die Variable nicht initialisiert ist.

Hoffe das hilft! :) :)

Elliott
quelle
0

defined?ist großartig, aber wenn Sie sich in einer Rails-Umgebung befinden, können Sie diese auch verwenden try, insbesondere in Fällen, in denen Sie einen dynamischen Variablennamen überprüfen möchten:

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