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.
Klassen und Module
Kann eine Klassendefinition wiederholt werden?
Eine Klasse kann wiederholt definiert werden. Jede Definition wird zur letzten Definition hinzugefügt. Wenn eine Methode neu definiert wird, wird die frühere überschrieben und geht verloren.
Gibt es Klassenvariablen?
Ja, die gibt es. Eine Variable, der zwei At-Zeichen (@@) vorangestellt sind, ist eine Klassenvariable, die sowohl innerhalb von Instanz- als auch von Klassenmethoden der Klasse zugänglich ist.
class Entity
@@instances = 0
def initialize
@@instances += 1
@number = @@instances
end
def who_am_i
"I'm #{@number} of #{@@instances}"
end
def self.total
@@instances
end
end
entities = Array.new(9) { Entity.new }
entities[6].who_am_i # => "I'm 7 of 9"
Entity.total # => 9
Sie sollten jedoch wahrscheinlich stattdessen Klasseninstanzvariablen verwenden.
Was ist eine Klasseninstanzvariable?
Hier ist das Beispiel des vorherigen Abschnitts, neu geschrieben mit einer Klasseninstanzvariable.
class Entity
@instances = 0
class << self
attr_accessor :instances # provide class methods for reading/writing
end
def initialize
self.class.instances += 1
@number = self.class.instances
end
def who_am_i
"I'm #{@number} of #{self.class.instances}"
end
def self.total
@instances
end
end
entities = Array.new(9) { Entity.new }
entities[6].who_am_i # => "I'm 7 of 9"
Entity.instances # => 9
Entity.total # => 9
Hier ist @instances eine Klasseninstanzvariable. Sie gehört nicht zu einer Instanz der Klasse Entity, sondern zum Klassenobjekt Entity, das eine Instanz der Klasse Class ist.
Klasseninstanzvariablen sind direkt nur innerhalb von Klassenmethoden der Klasse zugänglich.
Was ist der Unterschied zwischen Klassenvariablen und Klasseninstanzvariablen?
Der Hauptunterschied liegt im Verhalten in Bezug auf Vererbung: Klassenvariablen werden zwischen einer Klasse und all ihren Unterklassen geteilt, während Klasseninstanzvariablen nur einer bestimmten Klasse gehören.
Klassenvariablen können in gewisser Weise als globale Variablen im Kontext einer Vererbungshierarchie betrachtet werden, mit all den Problemen, die globale Variablen mit sich bringen. Beispielsweise kann eine Klassenvariable (versehentlich) von einer ihrer Unterklassen neu zugewiesen werden, was sich auf alle anderen Klassen auswirkt.
class Woof
@@sound = "woof"
def self.sound
@@sound
end
end
Woof.sound # => "woof"
class LoudWoof < Woof
@@sound = "WOOF"
end
LoudWoof.sound # => "WOOF"
Woof.sound # => "WOOF" (!)
Oder eine Oberklasse kann später wieder geöffnet und geändert werden, mit möglicherweise überraschenden Effekten.
class Foo
@@var = "foo"
def self.var
@@var
end
end
Foo.var # => "foo" (as expected)
class Object
@@var = "object"
end
Foo.var # => "object" (!)
Wenn Sie also nicht genau wissen, was Sie tun, und dieses Verhalten nicht explizit benötigen, sollten Sie besser Klasseninstanzvariablen verwenden.
Hat Ruby Klassenmethoden?
Eine Singleton-Methode eines Klassenobjekts wird als Klassenmethode bezeichnet. (Tatsächlich wird die Klassenmethode in der Metaklasse definiert, aber das ist weitgehend transparent.) Eine andere Sichtweise ist, dass eine Klassenmethode eine Methode ist, deren Empfänger eine Klasse ist.
Letztendlich können Sie Klassenmethoden aufrufen, ohne Instanzen dieser Klasse (Objekte) als Empfänger zu benötigen.
Lassen Sie uns eine Singleton-Methode der Klasse Foo erstellen.
class Foo
def self.test
"this is foo"
end
end
# It is invoked this way.
Foo.test # => "this is foo"
In diesem Beispiel ist Foo.test eine Klassenmethode.
Instanzmethoden, die in der Klasse Class definiert sind, können als Klassenmethoden für jede(!) Klasse verwendet werden.
Was ist eine Singleton-Klasse?
Eine Singleton-Klasse ist eine anonyme Klasse, die durch Unterklassenbildung der Klasse erstellt wird, die mit einem bestimmten Objekt verknüpft ist. Singleton-Klassen sind eine weitere Möglichkeit, die Funktionalität zu erweitern, die nur mit einem einzigen Objekt verbunden ist.
Nehmen Sie das einfache Foo.
class Foo
def hello
"hello"
end
end
foo = Foo.new
foo.hello # => "hello"
Nun sagen wir, wir müssen dieser einzelnen Instanz Funktionalität auf Klassenebene hinzufügen.
class << foo
attr_accessor :name
def hello
"hello, I'm #{name}"
end
end
foo.name = "Tom"
foo.hello # => "hello, I'm Tom"
Foo.new.hello # => "hello"
Wir haben foo angepasst, ohne die Eigenschaften von Foo zu ändern.
Was ist eine Modulfunktion?
Dieser Abschnitt oder Teile davon könnten veraltet oder nicht bestätigt sein.
Eine Modulfunktion ist eine private Singleton-Methode, die in einem Modul definiert ist. Im Wesentlichen ähnelt sie einer Klassenmethode, da sie mit der Notation Module.method aufgerufen werden kann.
Math.sqrt(2) # => 1.414213562
Da Module jedoch in Klassen gemischt werden können, können Modulfunktionen auch ohne Präfix verwendet werden (so werden alle Kernel-Funktionen für Objekte verfügbar gemacht).
include Math
sqrt(2) # => 1.414213562
Verwenden Sie module_function, um eine Methode zu einer Modulfunktion zu machen.
module Test
def thing
# ...
end
module_function :thing
end
Was ist der Unterschied zwischen einer Klasse und einem Modul?
Module sind Sammlungen von Methoden und Konstanten. Sie können keine Instanzen erzeugen. Klassen können Instanzen (Objekte) erzeugen und haben zustandsabhängige Instanzvariablen.
Module können in Klassen und andere Module gemischt werden. Die Konstanten und Methoden des gemischten Moduls verschmelzen mit denen der Klasse selbst und erweitern die Funktionalität der Klasse. Klassen können jedoch nicht in etwas gemischt werden.
Eine Klasse kann von einer anderen Klasse erben, aber nicht von einem Modul.
Ein Modul kann nicht von etwas erben.
Kann man Module unterklassen?
Nein. Ein Modul kann jedoch in eine Klasse oder ein anderes Modul aufgenommen werden, um Mehrfachvererbung zu simulieren (die Mixin-Einrichtung).
Dadurch wird keine Unterklasse erzeugt (was Vererbung erfordern würde), aber es entsteht eine is_a?-Beziehung zwischen der Klasse und dem Modul.
Geben Sie mir ein Beispiel für ein Mixin.
Das Modul Comparable bietet eine Vielzahl von Vergleichsoperatoren (<, <=, ==, >=, >, between?). Es definiert diese durch Aufrufe der allgemeinen Vergleichsmethode <=>. Es definiert jedoch <=> nicht selbst.
Nehmen wir an, Sie möchten eine Klasse erstellen, bei der Vergleiche auf der Anzahl der Beine eines Tieres basieren.
class Animal
include Comparable
attr_reader :legs
def initialize(name, legs)
@name, @legs = name, legs
end
def <=>(other)
legs <=> other.legs
end
def inspect
@name
end
end
c = Animal.new("cat", 4)
s = Animal.new("snake", 0)
p = Animal.new("parrot", 2)
c < s # => false
s < c # => true
p >= s # => true
p.between?(s, c) # => true
[p, s, c].sort # => [snake, parrot, cat]
Alles, was Animal tun muss, ist, seine eigene Semantik für den Operator <=> zu definieren und das Modul Comparable zu mischen. Die Methoden von Comparable werden nun von Animal nicht mehr zu unterscheiden sein, und Ihre Klasse erhält plötzlich neue Funktionalität. Und da dasselbe Modul Comparable von vielen Klassen verwendet wird, wird Ihre neue Klasse eine konsistente und gut verstandene Semantik teilen.
Warum gibt es zwei Möglichkeiten, Klassenmethoden zu definieren?
Sie können eine Klassenmethode in der Klassendefinition definieren, und Sie können eine Klassenmethode auf der obersten Ebene definieren.
class Demo
def self.class_method
end
end
def Demo.another_class_method
end
Es gibt nur einen wesentlichen Unterschied zwischen den beiden. In der Klassendefinition können Sie direkt auf die Konstanten der Klasse verweisen, da die Konstanten im Gültigkeitsbereich liegen. Auf der obersten Ebene müssen Sie die Notation Klasse::CONST verwenden.
Was ist der Unterschied zwischen include und extend?
Dieser Abschnitt oder Teile davon könnten veraltet oder nicht bestätigt sein.
include mischt ein Modul in eine Klasse oder ein anderes Modul. Methoden aus diesem Modul werden funktionsartig aufgerufen (ohne Empfänger).
extend wird verwendet, um ein Modul in ein Objekt (Instanz) einzufügen. Methoden im Modul werden zu Methoden des Objekts.
Was bedeutet self?
self ist der aktuell ausgeführte Empfänger, das Objekt, auf das eine Methode angewendet wird. Ein Funktionsaufruf impliziert self als Empfänger.