webentwicklung-frage-antwort-db.com.de

Was ist der Unterschied zwischen include und extend in Ruby?

Ich will nur Ruby Metaprogrammierung in den Kopf bekommen. Die Mixin/Module schaffen es immer, mich zu verwirren.

  • include: Mischt die angegebenen Modulmethoden als Instanzmethoden in die Zielklasse
  • extend: Mischt die angegebenen Modulmethoden als Klassenmethoden in die Zielklasse

Ist also der Hauptunterschied genau dies 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!"
392
Gishu

Was Sie gesagt haben, ist richtig. Es steckt jedoch noch mehr dahinter.

Wenn Sie eine Klasse Klazz und ein Modul Mod haben, einschließlich Mod in Klazz, erhalten Sie Instanzen von Klazz Zugriff auf Mods Methoden. Oder Sie können Klazz erweitern, indem Sie Mod angeben, dass KlasseKlazz auf die Methoden von Mod zugreifen soll. Sie können aber auch ein beliebiges Objekt mit o.extend Mod Erweitern. In diesem Fall ruft das einzelne Objekt die Methoden von Mod ab, obwohl alle anderen Objekte mit derselben Klasse wie o dies nicht tun.

238
domgblackwell

extend - fügt die Methoden und Konstanten des angegebenen Moduls der Metaklasse des Ziels (d. h. der Singleton-Klasse) hinzu, z.

  • wenn Sie Klazz.extend(Mod) aufrufen, hat Klazz jetzt Mods Methoden (als Klassenmethoden)
  • wenn Sie obj.extend(Mod) aufrufen, hat obj jetzt Mods Methoden (als Instanzmethoden), aber keine andere Instanz von obj.class hat diese Methoden hinzugefügt.
  • extend ist eine öffentliche Methode

include - Standardmäßig werden die Methoden des angegebenen Moduls als Instanzmethoden im Zielmodul/in der Zielklasse gemischt. z.B.

  • wenn Sie class Klazz; include Mod; end; aufrufen, 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.

Allerdings , Module sehr oft überschreibeninclude 's Verhalten durch Affen-Patching der included Methode. Dies ist in Legacy Rails Code. weitere Details von Yehuda Katz sehr wichtig.

Weitere Details zu include mit seinem Standardverhalten, vorausgesetzt, Sie haben den folgenden Code ausgeführt

class Klazz
  include Mod
end
  • Wenn Mod bereits in Klazz oder einem seiner Vorfahren enthalten ist, hat die include-Anweisung keine Auswirkung
  • Es enthält auch Mods Konstanten in Klazz, sofern sie nicht kollidieren
  • Es gibt Klazz Zugriff auf die Modulvariablen von Mod, z. @@foo Oder @@bar
  • löst ArgumentError aus, wenn zyklische Includes vorhanden sind
  • Fügt das Modul als direkten Vorfahren des Aufrufers hinzu (dh, es fügt Mod zu Klazz.ancestors hinzu, aber Mod wird nicht zur Kette von Klazz.superclass.superclass.superclass hinzugefügt. Wenn Sie also super in Klazz # foo aufrufen, wird dies überprüft für Mod # foo, bevor Sie die foo-Methode von Klazz überprüfen (siehe RubySpec für Details).

Natürlich ist die Ruby Kerndokumentation immer der beste Ort, um diese Dinge zu erledigen. Das RubySpec-Projekt war auch eine fantastische Ressource, weil sie die Funktionalität genau dokumentiert haben.

308
John Douthat

Das ist richtig.

Include ist eigentlich ein Alias ​​für append_features, das (aus den Dokumenten):

Rubys Standardimplementierung besteht darin, die Konstanten, Methoden und Modulvariablen dieses Moduls zu aModule hinzuzufügen, falls dieses Modul noch nicht zu aModule oder einem seiner Vorfahren hinzugefügt wurde.

14
Toby Hede

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 include module ReusableModule in der Klasse ClassThatIncludes angeben, wird auf die Methoden, Konstanten, Klassen, Submodule und andere Deklarationen verwiesen.

Wenn Sie Erweitern class ClassThatExtends with module ReusableModule, dann erhalten die Methoden und Konstanten Kopieren. 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 extended (kopiert) in die Include-Klasse.

3
Ho-Sheng Hsiao

Ich möchte auch den Mechanismus erklären, wie er funktioniert. Wenn ich nicht Recht habe, bitte korrigieren.

Wenn wir include verwenden, fügen wir eine Verknüpfung aus unserer Klasse zu einem Modul hinzu, das einige Methoden enthält.

class A
include MyMOd
end

a = A.new
a.some_method

Objekte haben keine Methoden, nur Klassen und Module. Wenn also a eine Meldung some_method Erhält, beginnt die Suchmethode some_method In der Eigenklasse von a, dann in der Klasse A und dann in verknüpft mit A Klassenmodule, falls vorhanden (in umgekehrter Reihenfolge, zuletzt eingeschlossene Gewinne).

Wenn wir extend verwenden, fügen wir eine Verknüpfung zu einem Modul in der Eigenklasse des Objekts hinzu. Wenn wir also A.new.extend (MyMod) verwenden, fügen wir eine Verknüpfung zu unserem Modul zur Instanz-Eigenklasse von A oder zur Klasse a' Hinzu. Und wenn wir A.extend (MyMod) verwenden, fügen wir eine Verknüpfung zu A hinzu (Objekte, Klassen sind auch Objekte). Eigenclass A'.

daher lautet der Methodensuchpfad für a 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 an A => A => enthaltenes Modul an A

entschuldigung für mein schlechtes Englisch.

1
user1136228