Die Programmiersprache Ruby (German Edition)
Fixnum # true: x ist eine Fixnum
x.is_a? Integer # true: x ist ein Integer
x.is_a? Numeric # true: x ist ein Numeric
x.is_a? Comparable # true: Funktioniert auch mit Mixin-Modulen
x.is_a? Object # true für jeden Wert von x
Die Klasse
Class
definiert den Operator
===
so, dass er anstelle von
is_a?
verwendet werden kann:
Numeric === x # true: x is_a Numeric
Diese Schreibweise ist eine Besonderheit von Ruby und ist wahrscheinlich schlechter lesbar als die traditionellere Methode
is_a?
.
Jedes Objekt hat in Ruby eine wohldefinierte Klasse, die sich während der Lebensdauer des Objekts niemals ändert. Der Typ eines Objekts ist dagegen beweglicher. Der Typ eines Objekts hat mit seiner Klasse zu tun, aber die Klasse ist nur ein Teil des Objekttyps. Wenn wir über den Typ eines Objekts sprechen, meinen wir die Menge von Verhaltensweisen, die das Objekt charakterisieren. Anders ausgedrückt, wird der Typ eines Objekts durch die Menge der Methoden bestimmt, auf die es reagieren kann. (Hier wird die Definition rekursiv, weil nicht nur die Namen der Methoden zählen, sondern auch die Typen der Argumente, die diese Methoden akzeptieren können.)
In der Ruby-Programmierung kümmern wir uns häufig nicht um die Klasse eines Objekts, sondern wollen lediglich wissen, ob wir eine bestimmte Methode dafür aufrufen können. Betrachten Sie beispielsweise den Operator
<<
. Arrays, Strings, Dateien und andere Klassen mit I/O-Bezug definieren ihn als Operator zum Anhängen von Werten. Wenn wir eine Methode schreiben, die Textausgaben erzeugt, können wir sie unter Verwendung dieses Operators generisch schreiben. Dann kann unsere Methode mit jedem Argument aufgerufen werden, das
<<
implementiert. Wir interessieren uns nicht für die Klasse des Arguments, sondern nur dafür, dass wir Werte daran anhängen können. Dies können wir mithilfe der Methode
respond_to?
überprüfen:
o.respond_to? :"<<" # true, wenn o einen <<-Operator besitzt
Der Nachteil dieses Ansatzes besteht darin, dass er nur den Namen einer Methode überprüft, aber nicht die Argumente für diese Methode. Sowohl
Fixnum
als auch
Bignum
implementieren
<<
beispielsweise als Linksverschiebungsoperator und erwarten eine Zahl statt eines String als Argument. Integer-Objekte sehen aus der Perspektive der
respond_to?
-Prüfung so aus, als könnte man Werte anhängen, aber sie erzeugen einen Fehler, wenn unser Code einen String anhängt. Es gibt keine allgemein gültige Lösung für dieses Problem, aber eine Ad-hoc-Abhilfe besteht in diesem Fall darin,
Numeric
-Objekte mithilfe der Methode
is_a?
explizit auszuschließen:
o.respond_to? :"<<" and not o.is_a? Numeric
Ein weiteres Beispiel für den Unterschied zwischen Typ und Klasse ist die Klasse
StringIO
aus der Ruby-Standardbibliothek.
StringIO
ermöglicht das Lesen aus und das Schreiben in String-Objekte, als seien sie
IO
-Objekte.
StringIO
ahmt die
IO
-API nach –
StringIO
-Objekte definieren dieselben Methoden wie
IO
-Objekte. Aber
StringIO
ist keine Unterklasse von
IO
. Wenn Sie eine Methode schreiben, die ein Datenstromargument erwartet, und die Klasse des Arguments mit
is_a? IO
überprüfen, dann funktioniert Ihre Methode nicht mit
StringIO
-Argumenten.
Die Konzentration auf Typen statt auf Klassen führt zu einem Programmierstil, der in Ruby als »Duck Typing« bezeichnet wird. In Kapitel 7 schauen wir uns Duck Typing-Beispiele an.
3.8.5 Objektgleichheit
Ruby besitzt eine überraschende Vielzahl von Möglichkeiten, Objekte auf Gleichheit zu überprüfen, und es ist wichtig zu verstehen, wie sie funktionieren, damit Sie wissen, wann welche Methode zum Einsatz kommen sollte.
3.8.5.1 Die Methode equal?
Die Methode
equal?
wird von
Object
definiert, um zu überprüfen, ob zwei Werte auf ein und dasselbe Objekt verweisen. Für zwei unterschiedliche Objekte gibt diese Methode stets
false
zurück:
a = "Ruby" # Eine Referenz auf ein String-Objekt
b = c = "Ruby" # Zwei Referenzen auf ein anderes String-Objekt
a.equal?(b) # false: a und b sind verschiedene Objekte
b.equal?(c) # true: b und c verweisen auf dasselbe Objekt
Per Konvention überschreiben Unterklassen niemals die Methode
equal?
.
Eine weitere Möglichkeit, um herauszufinden, ob zwei Objekte tatsächlich dasselbe Objekt sind, besteht darin, ihre
object_id
zu überprüfen:
a.object_id == b.object_id # Funktioniert wie a.equal?(b)
3.8.5.2 Der Operator ==
Der Operator
==
ist die gängigste Methode, um Gleichheit zu überprüfen. In der Klasse
Object
ist er
Weitere Kostenlose Bücher