Wenn du zum ersten Mal Ruby-Code siehst, wird er dich wahrscheinlich an andere Programmiersprachen erinnern, die du benutzt hast. Das ist Absicht. Der größte Teil der Syntax ist (unter anderem) Perl-, Python- und Java-Programmierern vertraut. Wenn du diese Sprachen also schon mal benutzt hast, wird das Lernen von Ruby ein Kinderspiel.
Dieses Dokument besteht aus zwei Teilen: Der erste versucht, eine Dauerfeuer-Zusammenfassung darüber zu geben, was dich erwartet, wenn du von Sprache X zu Ruby wechselst. Der zweite Teil geht auf die Hauptbestandteile von Ruby ein und vergleicht sie mit Konstrukten anderer Sprachen, die du bereits kennst.
Von Sprache X zu Ruby: Was erwartet mich?
Wichtige Features und ein paar Fallen
Hier sind ein paar Hinweise zu wichtigen Ruby-Features, denen du beim Lernen begegnen wirst.
Iteration
Zwei Dinge, denen du in dieser Form vermutlich noch nicht begegnet bist,
und an die man sich ein wenig gewöhnen muss, sind Blöcke und Iteratoren.
In Ruby iteriert man weder über einen Index (wie in C), noch über eine
Liste (wie in Perls for (@a) {...}
oder Pythons for item in aList:
),
sondern in den meisten Fällen so:
Mehr zu each
(und seine Artgenossen collect
/map
, find
, inject
,
sort
etc.) erfährst du über ri Enumerable
(bzw. ri Enumerable#methodenname
).
Alles hat einen Wert
Es gibt in Ruby keinen Unterschied zwischen einem Ausdruck und einer
Anweisung. Alles hat einen Wert, auch wenn er manchmal nur nil
ist.
Damit ist so etwas möglich:
Symbole sind keine Strings
Viele Ruby-Anfänger kämpfen damit, zu verstehen, was Symbole sind und wofür sie benutzt werden können.
Symbole sind am einfachsten als Identitäten (IDs) zu verstehen. Bei
einem Symbol ist wichtig, wer es ist, nicht was es ist. Starte irb
und du siehst den Unterschied:
Die Methode object_id
liefert die ID eines Objektes. Haben zwei
Objekte dieselbe object_id
, dann sind sie identisch (zeigen auf
dasselbe Objekt im Speicher.)
Wie du siehst, zeigt jedes gleichnamige Symbol auf dasselbe Objekt im
Speicher, und zwar von dem Moment an, in dem du das Symbol zum ersten
mal benutzt. Zwei Symbole mit denselben Zeichen haben die selbe object_id
.
Die Strings hingegen ("george"
) haben eine unterschiedliche object_id
.
Das bedeutet, dass sie auf zwei verschiedene Objekte im Speicher zeigen.
Immer wenn du einen neuen String benutzt, reserviert Ruby dafür Speicher.
Wenn du nicht genau weißt, ob du ein Symbol oder einen String brauchst, überlege dir, was wichtiger ist: die Identität des Objektes (z. B. ein Schlüssel in einem Hash) oder sein Inhalt (“george” im obigen Beispiel).
Alles ist ein Objekt
Das ist keine Übertreibung. Sogar Klassen und Zahlen sind Objekte, und du kannst mit ihnen dasselbe tun wie mit jedem anderen Objekt:
Variable Konstanten
Konstanten sind in Ruby nicht wirklich konstant. Wenn du eine schon initialisierte Konstante veränderst, wird eine Warnung erzeugt, aber das Programm läuft weiter. Was nicht heißt, dass du Konstanten umdefinieren solltest.
Namenskonventionen
Ruby erzwingt einige Namenskonventionen. Wenn ein Bezeichner mit einem
Großbuchstaben beginnt, dann ist er eine Konstante. Beginnt er mit einem
Dollarzeichen ($
), dann ist er eine globale Variable. Wenn er mit @
anfängt, ist es eine Instanzvariable, und Klassenvariablen beginnen mit
@@
.
Methodennamen dürfen allerdings auch mit einem Großbuchstaben beginnen. Das kann zu Verwirrung führen, wie das folgende Beispiel zeigt:
Nun hat Constant
den Wert 10, aber die Funktion Constant()
gibt 11
aus.
Nützlich ist dies, wenn man eine Methode genauso nennen möchte wie eine Klasse. Die folgenden Aufrufe generieren drei mal dasselbe Array mit den Zahlen von 1 bis 5:
Benannte Argumente
Seit Ruby 2.0 können Methoden wie auch in Python mit benannten Argumenten (Keyword-Argumenten) aufgerufen werden:
Die reine Wahrheit
In Ruby wird alles außer nil
und false
als Wahr (true) behandelt. In
C, Python und vielen anderen Sprachen verhalten sich die Zahl 0, leere
Listen und andere Werte als Unwahr (false). Sieh dir dazu folgenden
Python-Code an (das Beispiel funktioniert auch in anderen Sprachen):
Hier wird “0 ist false” ausgeben. Dasselbe in Ruby:
Ruby gibt “0 ist true” aus.
Sichtbarkeits-Modifikatoren gelten bis zum Ende des Blocks
Im folgenden Ruby-Code:
könnte man erwarten, dass another_method
public ist. Falsch.
private
gilt bis zum Ende des Blocks, oder bis ein anderer Modifikator
aufgerufen wird. Standardmäßig sind Methoden public:
public
, private
und protected
sind in Wirklichkeit Methoden und akzeptieren Parameter. Wenn du ein Symbol an eine davon übergibst, wird die Sichtbarkeit der Methode mit diesem Namen geändert:
Sichtbarkeit von Methoden
In Java bedeutet public, dass jeder eine Methode aufrufen darf. protected bedeutet, dass nur die Klasse selbst, ihre Instanzen und von ihr abgeleitete Klassen und deren Instanzen Zugriff haben. private beschränkt den Zugriff ganz auf die Klasse und ihre Instanzen.
Ruby verhält sich anders. public ist natürlich öffentlich. private
bedeutet, dass die Methode nicht mit einem expliziten Empfänger
aufgerufen werden kann, mit anderen Worten: Der Empfänger ist immer
self
.
Bei protected muss man aufpassen: Eine so geschützte Methode kann ohne Empfänger in der Klasse und abgeleiteten Klassen aufgerufen werden (wie bei private), aber zusätzlich auch mit einer anderen Instanz dieser Klasse als Empfänger.
Ein Beispiel aus den Ruby Language FAQ:
Offene Klassen
Ruby-Klassen sind offen. Du kannst sie jeder Zeit verändern und ihnen
Methoden hinzufügen. Sogar eingebaute Klassen wie Integer
oder Object
(die Mutter aller Objekte) sind erweiterbar. ActiveSupport fügt Integer
viele Methoden zur Erzeugung von Zeitangaben hinzu:
Lustige Namen für Methoden
In Ruby dürfen Methoden mit einem Frage- oder Ausrufezeichen enden. Die
Konvention ist, dass Methoden, die auf eine Ja-Nein-Frage antworten, ein
Fragezeichen erhalten: Array#empty?
liefert true
, wenn das Array
leer ist. Potentiell gefährliche Methoden (die den Empfänger selbst
verändern wie String#reverse!
, oder das brutale exit!
) enden mit
einem Ausrufezeichen.
Aber nicht alle Methoden, die ihre Empfänger verändern, haben ein
Ausrufezeichen. Array#replace
ersetzt den Inhalt des Arrays mit dem
Inhalt eines anderen. Es macht wenig Sinn, eine derartige Methode zu
schreiben, die den Empfänger nicht verändert.
Singleton-Methoden
Singleton-Methoden sind Methoden für Objekte. Sie gehören nur zu dem Objekt, für das du sie definierst:
Fehlende Methoden
Ruby gibt nicht auf, wenn es zu einem Aufruf keine passende Methode
finden kann. Es ruft stattdessen die Methode method_missing
auf und
übergibt den Namen der fehlenden Methode und die Argumente.
Standardmäßig erzeugt method_missing
einen NameError
, aber du kannst
es umdefinieren, so dass es besser in deine Anwendung passt (was viele
Bibliotheken auch tun.) Hier ist ein Beispiel:
Der obige Code gibt nur die Details des Aufrufs aus, aber du kannst die Botschaft natürlich auch völlig anders behandeln.
Botschaften senden statt Funktionen aufrufen
Ein Methodenaufruf ist in Ruby in Wirklichkeit eine Botschaft an ein Objekt:
Blöcke sind Objekte, sie wissen es nur noch nicht
Blöcke werden überall in der Standardbibliothek benutzt. Um einen Block
aufzurufen, kannst du yield
benutzen, oder du machst eine
Proc
-Instanz daraus, indem du einen speziellen Parameter zur Signatur
hinzufügst:
Du kannst Blockobjekte auch außerhalb von Methodenaufrufen erzeugen,
indem du Proc.new
oder die Methode lambda
mit dem Block aufrufst.
In ähnlicher Weise können auch aus Methoden Objekte gemacht werden:
Operatoren sind syntaktischer Zucker
Die meisten Operatoren in Ruby sind nur Methodenaufrufe mit einer
speziellen Syntax (und ein paar Vorrangregeln). Du kannst zum Beispiel
die Methode +
für Integer
überschreiben:
Du brauchst kein operator+
oder ähnliches.
Du kannst sogar Elementzugriff in der Art eines Arrays ermöglichen, wenn
du die Methoden []
und []=
definierst. Um das unäre +
und -
zu
überschreiben (für Vorzeichen), musst du die Methoden +@
und -@
benutzen.
Die folgenden Operatoren sind kein syntaktischer Zucker. Sie sind keine Methoden, und können nicht umdefiniert werden:
Zudem sind +=
, *=
, usw. nur Abkürzungen für foo = foo + bar
,
foo = foo * bar
usw. und können deshalb auch nicht überschrieben werden.
Weiterlesen
Wenn du bereit für noch mehr Ruby-Wissen bist, dann schau dir die Dokumentation an.