Was ist der Unterschied zwischen include und extend in Ruby?
Frage
Just getting my head around Ruby metaprogramming.Mixins/Module immer gelingt, verwirren mich.
- gehören:mischt sich in das angegebene Modul Methoden Instanz-Methoden in der Ziel-Klasse
- verlängern:mischt sich in das angegebene Modul Methoden Klassenmethoden in der Ziel-Klasse
So ist der wesentliche Unterschied gerade dies oder ist eine größere Drachen lauern? z.B.
module ReusableModule
def module_method
puts "Module Method: Hi there!"
end
end
class ClassThatIncludes
include ReusableModule
end
class ClassThatExtends
extend ReusableModule
end
puts "Include"
ClassThatIncludes.new.module_method # "Module Method: Hi there!"
puts "Extend"
ClassThatExtends.module_method # "Module Method: Hi there!"
Lösung
Was Sie gesagt haben, ist richtig. Allerdings gibt es mehr als das.
Wenn Sie eine Klasse Klazz
und Modul Mod
, einschließlich Mod
in Klazz
gibt Fälle von Klazz
Zugriff auf Mod
Methoden. Oder Sie können Klazz
mit Mod
geben die Klasse Klazz
Zugriff auf Mod
Methoden erweitern. Aber auch Sie können ein beliebiges Objekt mit o.extend Mod
erweitern. In diesem Fall wird das einzelne Objekt bekommt Methoden des Mod
obwohl alle andere Objekte mit der gleichen Klasse wie o
dies nicht tun.
Andere Tipps
erweitern - fügt die Methoden des angegebenen Moduls und Konstanten des Ziels metaclass (das heißt die Singleton-Klasse) z.B.
- , wenn Sie
Klazz.extend(Mod)
anrufen, jetzt Klazz hat Mod Methoden (als Klassenmethoden) - , wenn Sie
obj.extend(Mod)
anrufen, jetzt obj hat Mod Methoden (wie zB Methoden), aber keine andere Instanz vonobj.class
diese Methoden hinzugefügt. -
extend
ist eine öffentliche Methode
ist - Standardmäßig mischt es in der Methoden des angegebenen Moduls als Instanzmethoden in der Ziel Modul / Klasse. z.
- , wenn Sie
class Klazz; include Mod; end;
nennen, jetzt alle Instanzen von Klazz Zugriff auf Methoden der Mod haben (wie zB Methoden) -
include
ist eine private Methode, weil es beabsichtigt ist aus dem Container-Klasse / Modul aufgerufen werden.
Doch , Module sehr häufig Überschreibung include
Verhalten von Affen Patchen die included
Methode. Dies ist sehr prominent in Legacy-Rails-Code. mehr Details von Yehuda Katz .
Weitere Informationen über include
mit seinem Standardverhalten, vorausgesetzt, Sie haben den folgenden Code ausführen
class Klazz
include Mod
end
- Wenn Mod bereits in Klazz enthalten ist, oder einer seiner Vorfahren, die Include-Anweisung hat keine Auswirkung
- Es enthält auch Mod Konstanten in Klazz, solange sie es nicht tun kollidieren
- Es gibt Klazz Zugriff auf Mod-Modul Variablen, zum Beispiel
@@foo
oder@@bar
- hebt Argument wenn es zyklisch enthält
- Hängt das Modul als die unmittelbaren Vorfahren des Anrufers (dh es Mod Klazz.ancestors fügt hinzu, aber Mod ist nicht auf die Kette von Klazz.superclass.superclass.superclass hinzugefügt. So wird prüfen Mod
super
in Klazz # foo Aufruf #foo vor dem Klazz wirklicher Superklasse foo Methode zu überprüfen. Siehe RubySpec für weitere Details.).
Natürlich die Dokumentation Rubin Kern ist immer der beste Ort, um gehen für diese Dinge. Das RubySpec Projekt auch eine fantastische Ressource war, weil sie die Funktionalität genau dokumentiert.
- #include href="https://github.com/ruby/rubyspec/blob/master/core/module/include_spec.rb" rel="noreferrer"> RubySpec RubyDoc
- #included href="https://github.com/ruby/rubyspec/blob/master/core/module/included_spec.rb" rel="noreferrer"> RubySpec RubyDoc
- #extend href="https://github.com/ruby/rubyspec/blob/master/core/kernel/extend_spec.rb" rel="noreferrer"> RubySpec RubyDoc
- #extended href="https://github.com/ruby/rubyspec/blob/master/core/module/extended_spec.rb" rel="noreferrer"> RubySpec RubyDoc
- #extend_object href="https://github.com/ruby/rubyspec/blob/master/core/module/extend_object_spec.rb" rel="noreferrer"> RubySpec RubyDoc
- #append_features href="https://github.com/ruby/rubyspec/blob/master/core/module/append_features_spec.rb" rel="noreferrer"> RubySpec RubyDoc
Das ist richtig.
Hinter den kulissen enthalten ist, ist eigentlich ein alias für append_features, der (aus der Dokumentation):
Ruby ' s Standard-Ausführung fügen Sie den Konstanten, Methoden und module Variablen dieses Modul aModule, wenn dieses Modul nicht bereits Hinzugefügt wurde zu aModule oder einer seiner Vorfahren.
Alle anderen Antworten sind gut, einschließlich der Spitze durch RubySpecs zu graben:
https://github.com/rubyspec/rubyspec/ Blob / Master / core / module / include_spec.rb
https://github.com/rubyspec/rubyspec/ Blob / Master / core / module / extend_object_spec.rb
Wie für Anwendungsfälle:
Wenn Sie sind Modul ReusableModule in Klasse ClassThatIncludes, die Methoden, Konstanten, Klassen, Submodule und andere Erklärungen wird verwiesen.
Wenn Sie erweitern Klasse ClassThatExtends mit Modul ReusableModule, dann werden die Methoden und Konstanten wird kopiert . Natürlich, wenn Sie nicht vorsichtig sind, können Sie eine Menge Speicher verschwenden, indem dynamisch Definitionen zu duplizieren.
Wenn Sie Active :: Sorge verwenden, die .included () Funktionalität können Sie die mit Klasse direkt umschreiben. Modul Class innen ein Anliegen bekommt erweitert (kopiert) in die darunter Klasse.
Ich möchte auch den Mechanismus erklären, wie es funktioniert. Wenn ich richtig bin nicht bitte korrigieren.
Wenn wir verwenden include
wir eine Verknüpfung von unserer Klasse zu einem Modul hinzufügen, die einige Methoden enthält.
class A
include MyMOd
end
a = A.new
a.some_method
Objekte Methoden nicht haben, nur clases und Module tun.
Also, wenn a
Mésage empfängt some_method
es Suchmethode some_method
in a
der Eigen Klasse beginnen, dann in A
Klasse und dann verknüpfen in Klassenmodulen A
wenn es einige gibt (in umgekehrter Reihenfolge, zuletzt gewinnt enthalten).
Wenn wir verwenden extend
wir Verknüpfung mit einem Modul in Objekteigen Klasse hinzufügen.
Also, wenn wir verwenden A.new.extend (MyMod) wir Bindung an unser Modul A der Instanz Eigen Klasse oder a'
Klasse hinzufügen.
Und wenn wir A.extend (MyMod) verwenden wir das Hinzufügen Verknüpfung zu A (Objekt, Klassen sind auch Objekte) Eigenklasse A'
.
so Methodennachschlag Weg für a
ist wie folgt:
a => a '=> Module zu einem verknüpften' class => A.
Auch gibt es eine Methode, die prepend Lookup Pfad ändert:
a => a‘=> vorangestellt modulesto A => A => enthalten Modul A
sorry für mein schlechtes Englisch.