Offizielle Ruby FAQ
Wenn Sie Fehler melden oder Verbesserungen für diese FAQ vorschlagen möchten, besuchen Sie bitte unser GitHub-Repository und öffnen Sie ein Issue oder einen Pull Request.
Variablen, Konstanten und Argumente
Erzeugt eine Zuweisung eine neue Kopie eines Objekts?
Alle Variablen und Konstanten verweisen auf ein Objekt. (Mit Ausnahme von nicht initialisierten lokalen Variablen, die auf nichts verweisen. Diese lösen eine NameError Ausnahme aus, wenn sie verwendet werden). Wenn Sie einer Variablen etwas zuweisen oder eine Konstante initialisieren, legen Sie das Objekt fest, auf das die Variable oder Konstante verweist.
Eine Zuweisung allein erstellt daher nie eine neue Kopie eines Objekts.
In bestimmten Sonderfällen gibt es eine etwas tiefere Erklärung. Instanzen von Fixnum, NilClass, TrueClass und FalseClass sind direkt in Variablen oder Konstanten enthalten – es ist keine Referenz beteiligt. Eine Variable, die die Zahl 42 oder die Konstante true enthält, enthält tatsächlich den Wert und nicht eine Referenz darauf. Eine Zuweisung erzeugt daher physisch eine Kopie von Objekten dieser Typen. Dies wird im Abschnitt Immediate and Reference Objects genauer erläutert.
Was ist der Gültigkeitsbereich einer lokalen Variable?
Ein neuer Gültigkeitsbereich für eine lokale Variable wird eingeführt in (1) der Top-Ebene (main), (2) einer Klassen- (oder Modul-) Definition oder (3) einer Methodendefinition.
var = 1 # (1)
class Demo
var = 2 # (2)
def method
var = 3 # (3)
puts "in method: var = #{var}"
end
puts "in class: var = #{var}"
end
puts "at top level: var = #{var}"
Demo.new.method
Erzeugt
in class: var = 2
at top level: var = 1
in method: var = 3
(Beachten Sie, dass die Klassendefinition ausführbarer Code ist: die darin enthaltene Trace-Nachricht wird beim Definieren der Klasse ausgegeben).
Ein Block ({ ... } oder do ... end) führt fast einen neuen Gültigkeitsbereich ein ;-) Lokale Variablen, die innerhalb eines Blocks erstellt werden, sind außerhalb des Blocks nicht zugänglich. Wenn jedoch eine lokale Variable innerhalb des Blocks den gleichen Namen wie eine vorhandene lokale Variable im Gültigkeitsbereich des Aufrufers hat, wird keine neue lokale Variable erstellt, und Sie können anschließend auf diese Variable außerhalb des Blocks zugreifen.
a = 0
1.upto(3) do |i|
a += i
b = i*i
end
a # => 6
# b is not defined here
Dies wird wichtig, wenn Sie Threading verwenden – jeder Thread erhält seine eigene Kopie der Variablen, die für den Block des Threads lokal sind.
threads = []
["one", "two"].each do |name|
threads << Thread.new do
local_name = name
a = 0
3.times do |i|
Thread.pass
a += i
puts "#{local_name}: #{a}"
end
end
end
threads.each {|t| t.join }
Könnte (falls der Scheduler die Threads wie von Thread.pass angedeutet wechselt; dies hängt vom Betriebssystem und Prozessor ab) erzeugt werden
one: 0
two: 0
one: 1
two: 1
one: 3
two: 3
while, until und for sind Kontrollstrukturen, keine Blöcke, daher sind lokale Variablen innerhalb von ihnen in der umgebenden Umgebung zugänglich. loop hingegen ist eine Methode und der zugehörige Block führt einen neuen Gültigkeitsbereich ein.
Wann wird eine lokale Variable zugänglich?
Eigentlich könnte die Frage besser gestellt werden als: „An welchem Punkt erkennt Ruby, dass etwas eine Variable ist?“ Das Problem entsteht, weil der einfache Ausdruck a entweder eine Variable oder ein Aufruf einer Methode ohne Parameter sein könnte. Um zu entscheiden, was der Fall ist, sucht Ruby nach Zuweisungsanweisungen. Wenn es an irgendeiner Stelle im Quellcode vor der Verwendung von a sieht, dass a zugewiesen wird, entscheidet es sich, a als Variable zu parsen, andernfalls behandelt es es als Methode. Als etwas pathologischer Fall davon betrachten Sie dieses Codefragment, das ursprünglich von Clemens Hintze eingereicht wurde.
def a
puts "method `a' called"
99
end
[1, 2].each do |i|
if i == 2
puts "a = #{a}"
else
a = 1
puts "a = #{a}"
end
end
Erzeugt
a = 1
method `a' called
a = 99
Während des Parsens sieht Ruby die Verwendung von a in der ersten puts-Anweisung und, da es noch keine Zuweisung an a gesehen hat, geht es davon aus, dass es sich um einen Methodenaufruf handelt. Bis es jedoch zur zweiten puts-Anweisung kommt, hat es eine Zuweisung gesehen und behandelt a daher als Variable.
Beachten Sie, dass die Zuweisung nicht ausgeführt werden muss – Ruby muss sie nur gesehen haben. Dieses Programm löst keinen Fehler aus.
a = 1 if false; a # => nil
Dieses Problem mit Variablen ist normalerweise kein Problem. Wenn Sie darauf stoßen, versuchen Sie, eine Zuweisung wie a = nil vor dem ersten Zugriff auf die Variable einzufügen. Dies hat den zusätzlichen Vorteil, dass die Zugriffszeit auf lokale Variablen, die anschließend in Schleifen vorkommen, beschleunigt wird.
Was ist der Gültigkeitsbereich einer Konstante?
Eine Konstante, die in einer Klassen- oder Moduldefinition definiert ist, kann direkt innerhalb der Definition dieser Klasse oder dieses Moduls aufgerufen werden.
Sie können Konstanten in äußeren Klassen und Modulen direkt aus verschachtelten Klassen und Modulen aufrufen.
Sie können auch direkt Konstanten in Oberklassen und eingebundenen Modulen aufrufen.
Abgesehen von diesen Fällen können Sie Klassen- und Modulkonstanten mit dem Operator ::, ModuleName::CONST1 oder ClassName::CONST2 aufrufen.
Wie werden Argumente übergeben?
Das tatsächliche Argument wird dem formalen Argument zugewiesen, wenn die Methode aufgerufen wird. (Siehe Zuweisung für mehr über die Semantik der Zuweisung.)
def add_one(number)
number += 1
end
a = 1
add_one(a) # => 2
a # => 1
Da Sie Objekt-Referenzen übergeben, ist es möglich, dass eine Methode den Inhalt eines veränderlichen Objekts, das ihr übergeben wurde, modifiziert.
def downer(string)
string.downcase!
end
a = "HELLO" # => "HELLO"
downer(a) # => "hello"
a # => "hello"
Es gibt kein Äquivalent zu den Pass-by-Reference-Semantiken anderer Sprachen.
Beeinflusst eine Zuweisung an ein formales Argument das tatsächliche Argument?
Ein formales Argument ist eine lokale Variable. Innerhalb einer Methode ändert eine Zuweisung an ein formales Argument einfach, dass das Argument auf ein anderes Objekt verweist.
Was passiert, wenn ich eine Methode über ein formales Argument aufrufe?
Alle Ruby-Variablen (einschließlich Methodendefinitionen) fungieren als Referenzen auf Objekte. Sie können Methoden auf diesen Objekten aufrufen, um den Zustand des Objekts zu erhalten oder zu ändern und das Objekt etwas tun zu lassen. Dies können Sie mit Objekten tun, die an Methoden übergeben werden. Seien Sie dabei vorsichtig, da solche Nebeneffekte Programme schwer nachvollziehbar machen können.
Was bedeutet das * vor einem Argument?
Wenn der Stern als Teil einer Liste formaler Parameter verwendet wird, ermöglicht er die Übergabe einer beliebigen Anzahl von Argumenten an eine Methode, indem diese in einem Array gesammelt und diesem Stern-Parameter zugewiesen werden.
def foo(prefix, *all)
all.each do |element|
puts "#{prefix}#{element}"
end
end
foo("val = ", 1, 2, 3)
Erzeugt
val = 1
val = 2
val = 3
Wenn er in einem Methodenaufruf verwendet wird, erweitert * ein Array und übergibt dessen einzelne Elemente als Argumente.
a = [1, 2, 3]
foo(*a)
Sie können * vor das letzte Argument von
- Linke Seite einer Mehrfachzuweisung.
- Rechte Seite einer Mehrfachzuweisung.
- Definition von formalen Methodenargumenten.
- Tatsächliche Argumente bei einem Methodenaufruf.
- In der
when-Klausel einercase-Struktur.
Zum Beispiel
x, *y = [7, 8, 9]
x # => 7
y # => [8, 9]
x, = [7, 8, 9]
x # => 7
x = [7, 8, 9]
x # => [7, 8, 9]
Was bedeutet das & vor einem Argument?
Wenn das letzte formale Argument einer Methode mit einem Ampersand (&) versehen ist, wird ein Block, der dem Methodenaufruf folgt, in ein Proc-Objekt konvertiert und dem formalen Parameter zugewiesen.
Wenn das letzte tatsächliche Argument bei einem Methodenaufruf ein Proc-Objekt ist, können Sie seinem Namen ein Ampersand voranstellen, um es in einen Block zu konvertieren. Die Methode kann dann yield verwenden, um es aufzurufen.
def meth1(&b)
puts b.call(9)
end
meth1 {|i| i + i }
def meth2
puts yield(8)
end
square = proc {|i| i * i }
meth2 {|i| i + i }
meth2 &square
Erzeugt
18
16
64
Wie kann ich einen Standardwert für ein formales Argument angeben?
def greet(p1="hello", p2="world")
puts "#{p1} #{p2}"
end
greet
greet("hi")
greet("morning", "mom")
Erzeugt
hello world
hi world
morning mom
Der Standardwert (der ein beliebiger Ausdruck sein kann) wird beim Aufruf der Methode ausgewertet. Er wird mit dem Gültigkeitsbereich der Methode ausgewertet.
Wie übergebe ich Argumente an einen Block?
Die formalen Parameter eines Blocks erscheinen zwischen senkrechten Strichen am Anfang des Blocks.
proc {|a, b| a <=> b }
Diese Parameter sind tatsächlich lokale Variablen. Wenn eine vorhandene lokale Variable mit demselben Namen existiert, wenn der Block ausgeführt wird, wird diese Variable durch den Aufruf des Blocks modifiziert. Das kann gut oder schlecht sein.
Typischerweise werden Argumente an einen Block über yield (oder einen Iterator, der yield aufruft) übergeben, oder durch Verwendung der Methode Proc.call.
Warum hat sich mein Objekt unerwartet geändert?
A = a = b = "abc"
b.concat("d") # => "abcd"
a # => "abcd"
A # => "abcd"
Variablen speichern Referenzen auf Objekte. Die Zuweisung A = a = b = "abc" legt eine Referenz auf den String "abc" in A, a und b ab.
Wenn Sie b.concat("d") aufrufen, rufen Sie die concat-Methode auf diesem Objekt auf und ändern es von "abc" zu "abcd". Da a und A ebenfalls auf dasselbe Objekt verweisen, ändern sich auch ihre scheinbaren Werte.
Dies ist in der Praxis weniger ein Problem, als es erscheinen mag.
Zusätzlich können alle Objekte eingefroren werden, was sie vor Änderungen schützt.
Ändert sich der Wert einer Konstante jemals?
Eine Konstante ist eine Variable, deren Name mit einem Großbuchstaben beginnt. Konstanten können nicht aus Instanzmethoden neu zugewiesen werden, können aber sonst nach Belieben geändert werden. Wenn einer Konstante ein neuer Wert zugewiesen wird, wird eine Warnung ausgegeben.
Warum kann ich keine Variablen aus einer separaten Datei laden?
Angenommen, file1.rb enthält
var1 = 99
und eine andere Datei lädt sie ein
require_relative "file1"
puts var1
Erzeugt
prog.rb:2:in `<main>': undefined local variable or method `var1' for main:Object (NameError)
Sie erhalten einen Fehler, weil load und require dafür sorgen, dass lokale Variablen in einem separaten, anonymen Namensraum gespeichert werden, wodurch sie effektiv verworfen werden. Dies dient dem Schutz Ihres Codes vor Verunreinigung.