Nachdruck aus Blog-Artikel.
Kürzlich habe ich ein paar Leute geschrieben, die davon abhängig sind, deshalb werde ich es für einen Moment zusammenfassen.
In Ruby können Sie beim Aufrufen einer Methode "die Methode aufrufen, indem Sie" () "weglassen" im Vergleich zu anderen Sprachen.
def hoge(a = nil)
"#hoge(#{a})"
end
#Sie können eine Methode ohne Klammern aufrufen
p hoge
# => "#hoge()"
#Sie können auch bei einem methodenähnlichen Aufruf auf die Methode verweisen
p hoge() # => "#hoge()"
p hoge 42 # => "#hoge(42)"
p self.hoge # => "#hoge()"
Nun, das ist richtig.
Das Problem ist, wenn "Methoden und Variablen mit demselben Namen" gemischt werden. In diesem Fall beziehen Sie sich auf "Variable, wenn auf die Variable verwiesen werden kann" und "Andernfalls".
def hoge(a = nil)
"#hoge(#{a})"
end
#Da zu diesem Zeitpunkt keine Variablen definiert sind, wird die Methode mit Priorität aufgerufen.
p hoge # => #hoge()
#Variablen definieren
hoge = 42
#Geben Sie der Variablen nach dem Definieren der Variablen Priorität.
p hoge # => 42
#Rufen Sie in einem methodenähnlichen Aufruf die Methode auf
p hoge() # => "#hoge()"
p hoge 42 # => "#hoge(42)"
p self.hoge # => "#hoge()"
Beachten Sie zu diesem Zeitpunkt, dass "Methode vor dem Zuweisungsausdruck" und "Variable vor dem Zuweisungsausdruck".
In Ruby gibt es beispielsweise einen Fall, in dem der Prozess, der die Variable tatsächlich definiert, nicht wie folgt aufgerufen wird.
def hoge(a = nil)
"#hoge(#{a})"
end
if false
hoge = 42
end
#Ist das eine Methodenreferenz?
p hoge
In der Interpretersprache kann erwartet werden, dass dies "die Methode wird aufgerufen, weil die Variable nicht definiert ist".
In der Realität bezieht sich "p hoge" jedoch auf die "Variable" hoge ".
Dies ist ein Geheimnis dafür, wie Ruby den Quellcode ausführt.
Bevor Sie in Ruby den Quellcode ausführen, "analysieren Sie zuerst den gesamten Ruby-Quellcode" und führen Sie dann den Ruby-Code aus.
Wie der obige Code ist die Variable "hoge" implizit, wenn der "Zuweisungsausdruck" definiert wird, da der gesamte Quellcode analysiert wird, unabhängig davon, "ob der Code zur Laufzeit aufgerufen wird". Es wird in definiert.
Unabhängig davon, ob der Inhalt der if-Anweisung tatsächlich aufgerufen wird, wird die "Variable hoge
" daher als "außerhalb der if-Anweisung" bezeichnet, wenn der "Zuweisungsausdruck" definiert wird.
#Tatsächliches Ausführungsergebnis
def hoge(a = nil)
"#hoge(#{a})"
end
if false
hoge = 42
end
#Referenzvariablen hier
#Gibt nil zurück, da der Standardwert der Variablen nil ist
p hoge
# nil
Es ist sehr schwer zu verstehen, wie Ruby den Quellcode analysiert. Was passiert zum Beispiel, wenn Sie "eine" hoge "-Variable definieren, während Sie wie folgt auf" hoge "mit einem Postfix if" verweisen?
hoge = 42 if hoge.nil?
p hoge
Viele Leute denken, dass dies daran liegt, dass "if hoge.nil?" Vor der Variablendefinition verarbeitet wird, sodass der Prozess "hoge = 42" nicht tatsächlich aufgerufen wird. In Wirklichkeit wird der Code "hoge = 42 if hoge.nil?" Als "dies ist insgesamt ein Prozess" analysiert. Wenn "if hoge.nil?" Aufgerufen wird, wurde der Code "hoge = 42" bereits analysiert, und der Prozess lautet "Die Variable" hoge "ist definiert". Das Ergebnis der Ausführung des obigen Codes ist also
hoge = 42 if hoge.nil?
p hoge
# => 42
Dann wird " hoge = 42
"verarbeitet.
Wenn es sich hingegen nicht um ein Postfix handelt, ist das Ergebnis anders, sodass Sie vorsichtig sein müssen.
#Dies führt zu einem Fehler
# error: undefined local variable or method `hoge' for main:Object (NameError)
if hoge.nil?
hoge = 42
end
Dies liegt daran, dass "if hoge.nil?" Vor der Variablen analysiert wird und der bedingte Ausdruck der if-Anweisung "in dem Zustand ausgeführt wird, in dem die Variable nicht definiert ist".
In Ruby gibt es eine Methode namens "eval". Dies ist die Methode, mit der der Ruby-Quellcode "zur Laufzeit" ausgeführt wird.
def hoge(a = nil)
"#hoge(#{a})"
end
hoge = 42
#Führen Sie die an eval übergebene Zeichenfolge als Ruby-Code aus
p eval("hoge + hoge")
# => 84
Wenn der obige Code ausgeführt wird, wird nach dem Zuweisungsausdruck "hoge + hoge" ausgeführt. Siehe daher "Variable". Was passiert also, wenn Sie Code wie folgt ausführen:
def hoge(a = nil)
"#hoge(#{a})"
end
#Führen Sie hoge vor dem Zuweisungsausdruck aus
p eval("hoge")
hoge = 42
Aus dem zuvor erläuterten Ablauf "Ich führe" "hoge" "vor der Variablen" aus, daher erwarte ich, dass dies ein "Methodenaufruf" ist. Wenn es jedoch tatsächlich ausgeführt wird, ist das Ergebnis wie folgt.
def hoge(a = nil)
"#hoge(#{a})"
end
#Verweisen Sie auf Variablen anstelle von Methodenaufrufen
p eval("hoge")
# => nil
hoge = 42
Der Grund für dieses Ergebnis ist, dass das "Timing des Ruby-Quellcodes" und das "Timing der Ausführung von" eval "unterschiedlich sind.
Der Zeitpunkt für die Ausführung von "eval" ist "zum Zeitpunkt der Ausführung von Ruby".
Diese "Laufzeit" ist "nachdem der Ruby-Quellcode analysiert wurde".
Mit anderen Worten, da "Timing to Execute Eval
" bereits "nach dem Parsen des Ruby-Quellcodes" ist, bezieht sich der Ausdruck "Hoge" auf "Variablen zuerst".
Wenn daher eine Variable oder Methode aus "eval" referenziert wird, wird die "Variable" unabhängig von der "Definitionsposition des Zuweisungsausdrucks" mit Priorität aufgerufen.
Dies wirkt sich auch auf die Verwendung von "binding.irb" aus. Dies ist ein Problem, wenn "binding.irb" "vor dem Zuweisungsausdruck" aufgerufen wird. Beispiel:
def hoge(a = nil)
"#hoge(#{a})"
end
#Bindung zum Debuggen etc..Starten Sie irb zur Laufzeit mit irb
#Wenn Sie sich auf hoge auf dieser irb-Konsole beziehen, sehen Sie "Variablen".
binding.irb
hoge = 42
binding.irb
verwendet eval
, um den eingegebenen Ruby-Code auszuführen.
Daher wird es unter Bezugnahme auf die "Variable" wie im vorherigen Beispiel ausgeführt.
Ich denke, es ist selten, "eval" in normalem Ruby-Code zu verwenden, aber Sie müssen vorsichtig sein, da die Verwendung von "binding.irb" usw. indirekt die Verwendung von "eval" bedeutet. ..
Also habe ich versucht, die Ruby-Variablen zusammenzufassen. Wenn Sie tatsächlich eine Methode mit "binding.irb" aufrufen, wird möglicherweise "nil" zurückgegeben. Wenn Sie sich den Code genau ansehen, wird nach "binding.irb" ein gleichnamiger Variablenname definiert. Da war etwas. Wie Sie sehen können, gibt es in Ruby einige süchtig machende Punkte. Seien Sie also vorsichtig.
Recommended Posts