Ich beschäftige mich nur mit Ruby-Metaprogrammierung. Das Mixin / die Module schaffen es immer, mich zu verwirren.
- include : mischt bestimmte Modulmethoden als Instanzmethoden in der Zielklasse ein
- verlängern : mischt angegebene Modulmethoden als Klassenmethoden in der Zielklasse ein
Ist der Hauptunterschied genau das oder lauert ein größerer Drache? 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!"
Antworten:
Was Sie gesagt haben, ist richtig. Es steckt jedoch noch mehr dahinter.
Wenn Sie eine Klasse haben
Klazz
und ModulMod
, einschließlichMod
inKlazz
gibt InstanzenKlazz
Zugriff aufMod
‚s Methoden. Oder Sie können erweiternKlazz
mitMod
Angabe der KlasseKlazz
Zugriff aufMod
‚s Methoden. Sie können aber auch ein beliebiges Objekt mit erweiterno.extend Mod
. In diesem Fall erhält das einzelne ObjektMod
die Methoden, obwohl alle anderen Objekte dieselbe Klasse haben wieo
nicht.quelle
verlängern - Fügt die Methoden und Konstanten des angegebenen Moduls zur Metaklasse des Ziels hinzu (dh zur Singleton-Klasse), z
Klazz.extend(Mod)
, hat Klazz jetzt Mods Methoden (als Klassenmethoden)obj.extend(Mod)
, hat obj jetzt Mods Methoden (als Instanzmethoden), aber keine andere Instanz vonobj.class
hat diese Methoden hinzugefügt.extend
ist eine öffentliche Methodeinclude - Standardmäßig werden die Methoden des angegebenen Moduls als Instanzmethoden im Zielmodul / in der Zielklasse gemischt. z.B
class Klazz; include Mod; end;
, haben jetzt alle Instanzen von Klazz Zugriff auf Mods Methoden (als Instanzmethoden).include
ist eine private Methode, da sie innerhalb der Containerklasse / des Containermoduls aufgerufen werden soll.Module überschreiben jedoch sehr oft das
include
Verhalten, indem sie dieincluded
Methode mit Affen patchen . Dies ist im alten Rails-Code sehr wichtig. Weitere Details von Yehuda Katz .Weitere Details zu
include
, mit dem Standardverhalten, vorausgesetzt, Sie haben den folgenden Code ausgeführt@@foo
oder@@bar
super
Klazz # foo aufrufen, wird vor dem Überprüfen nach Mod # foo gesucht zu Klazz 'foo-Methode der echten Superklasse. Siehe RubySpec für Details.).Natürlich ist die Ruby Core-Dokumentation immer der beste Ort für diese Dinge. Das RubySpec-Projekt war auch eine fantastische Ressource, da es die Funktionalität genau dokumentierte.
#include
RubySpec rubydoc#included
RubySpec rubydoc#extend
RubySpec rubydoc#extended
RubySpec rubydoc#extend_object
RubySpec rubydoc#append_features
RubySpec rubydocquelle
extend
als Klassen- oder Instanzmethoden angewendet werden können .Klass.extend
= Klassenmethoden,objekt.extend
= Instanzmethoden. Ich habe immer (fälschlicherweise) angenommen, dass Klassenmethoden vonextend
und Instanz von stammeninclude
.Das ist richtig.
Hinter den Kulissen befindet sich ein Alias für append_features , der (aus den Dokumenten):
quelle
Wenn Sie
include
ein Modul in eine Klasse einbinden, werden die Modulmethoden als Instanzmethoden importiert .Wenn Sie jedoch
extend
ein Modul in eine Klasse einbinden, werden die Modulmethoden als Klassenmethoden importiert .Zum Beispiel, wenn wir ein Modul
Module_test
wie folgt definiert haben:Nun zum
include
Modul. Wenn wir die KlasseA
wie folgt definieren:Die Ausgabe lautet :
M - in module
.Wenn wir die Zeile
include Module_test
durch ersetzenextend Module_test
und den Code erneut ausführen, wird die folgende Fehlermeldung angezeigt :undefined method 'func' for #<A:instance_num> (NoMethodError)
.Wenn Sie den Methodenaufruf
a.func
inA.func
ändern, ändert sich die Ausgabe in :M - in module
.Aus der obigen Codeausführung geht hervor, dass wenn wir
include
ein Modul sind, seine Methoden zu Instanzmethoden werden und wenn wirextend
ein Modul sind, seine Methoden zu Klassenmethoden werden .quelle
Alle anderen Antworten sind gut, einschließlich des Tipps zum Durchsuchen von RubySpecs:
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 das Modul ReusableModule in die Klasse ClassThatIncludes aufnehmen, wird auf die Methoden, Konstanten, Klassen, Submodule und andere Deklarationen verwiesen.
Wenn Sie die Klasse ClassThatExtends mit dem Modul ReusableModule erweitern, werden die Methoden und Konstanten kopiert . Wenn Sie nicht aufpassen, können Sie natürlich viel Speicher verschwenden, indem Sie Definitionen dynamisch duplizieren.
Wenn Sie ActiveSupport :: Concern verwenden, können Sie mit der Funktion .included () die Include-Klasse direkt neu schreiben. Das Modul ClassMethods in einem Concern wird in die Inclusive- Klasse erweitert (kopiert).
quelle
Ich möchte auch den Mechanismus erklären, wie er funktioniert. Wenn ich nicht richtig liege, bitte korrigieren.
Wenn wir verwenden
include
, fügen wir eine Verknüpfung aus unserer Klasse zu einem Modul hinzu, das einige Methoden enthält.Objekte haben keine Methoden, nur Klassen und Module. Wenn also
a
eine Nachricht empfangen wirdsome_method
, beginnt die Suchmethodesome_method
in der Eigenklassea
, dann in derA
Klasse und dann in den mitA
Klassenmodulen verknüpften Modulen, falls vorhanden (in umgekehrter Reihenfolge, zuletzt eingeschlossene Gewinne).Wenn wir verwenden
extend
, fügen wir einem Modul in der Eigenklasse des Objekts eine Verknüpfung hinzu. Wenn wir also A.new.extend (MyMod) verwenden, fügen wir unserem Modul eine Verknüpfung zur Instanzeigenklasse oder -klasse von A hinzua'
. Und wenn wir A.extend (MyMod) verwenden, fügen wir eine Verknüpfung zur A-Eigenklasse (Objekte, Klassen sind auch Objekte) hinzuA'
.Der Pfad für die Methodensuche
a
lautet also wie folgt: a => a '=> verknüpfte Module mit einer' Klasse => A.Es gibt auch eine Prepend-Methode, die den Suchpfad ändert:
a => a '=> vorangestelltes Modul für A => A => enthaltenes Modul für A.
Entschuldigung für mein schlechtes Englisch.
quelle