Właśnie omijałem metaprogramowanie Ruby. Mixin / moduły zawsze potrafią mnie pomylić.
- include : miksy w określonych metodach modułów jako metody instancji w klasie docelowej
- ext : miksuje w określonych metodach modułowych jako metodach klasy w klasie docelowej
Więc czy jest to główna różnica, czy może czai się większy smok? na przykład
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!"
Odpowiedzi:
To, co powiedziałeś, jest poprawne. Jest jednak coś więcej.
Jeśli masz klasę
Klazz
i modułMod
, w tymMod
inKlazz
daje przypadkiKlazz
dostępu doMod
metod. Czy można przedłużyćKlazz
zMod
podaniem klasyKlazz
dostępu doMod
„s metod. Ale możesz także rozszerzyć dowolny obiekt za pomocąo.extend Mod
. W tym przypadku pojedynczy obiekt pobieraMod
metody, mimo że wszystkie inne obiekty z tą samą klasą, coo
nie.źródło
expand - dodaje metody i stałe określonego modułu do metaklasy celu (tj. klasy singleton) np
Klazz.extend(Mod)
, teraz Klazz ma metody Mod (jako metody klasowe)obj.extend(Mod)
, teraz obj ma metody Mod (jako metody instancji), ale żadna inna instancja nieobj.class
ma tych metod dodanych.extend
jest metodą publicznąinclude - Domyślnie miesza się w metodach określonego modułu jako metod instancji w module / klasie docelowej. na przykład
class Klazz; include Mod; end;
, teraz wszystkie instancje Klazz mają dostęp do metod Mod (jako metod instancji)include
jest metodą prywatną, ponieważ ma być wywoływana z klasy / modułu kontenera.Jednak moduły bardzo często zastępują
include
zachowanie, dokonując łataniaincluded
metody małp . Jest to bardzo widoczne w starszym kodzie Railsów. więcej szczegółów od Yehuda Katz .Więcej informacji na temat
include
domyślnego zachowania przy założeniu, że uruchomiłeś następujący kod@@foo
Lub@@bar
super
Klazz # foo sprawdzi Mod # foo przed sprawdzeniem do metody foo prawdziwej nadklasy Klazza. Szczegółowe informacje można znaleźć w RubySpec.).Oczywiście dokumentacja ruby jest zawsze najlepszym miejscem na te rzeczy. Projekt RubySpec był również fantastycznym zasobem, ponieważ dokładnie dokumentowali funkcjonalność.
#include
RubySpec rubydoc#included
RubySpec rubydoc#extend
RubySpec rubydoc#extended
RubySpec rubydoc#extend_object
RubySpec rubydoc#append_features
RubySpec rubydocźródło
extend
zastosowania metod jako metod klasy lub instancji, w zależności od wykorzystania.Klass.extend
= metody klas,objekt.extend
= metody instancji. Zawsze (błędnie) zakładałem, że metody klas pochodzą zextend
instancjiinclude
.To jest poprawne.
Za kulisami, include to tak naprawdę alias dla append_features , który (z dokumentacji):
źródło
Po przejściu
include
modułu do klasy metody modułu są importowane jako metody instancji .Jednak po przejściu
extend
modułu do klasy metody modułu są importowane jako metody klasy .Na przykład, jeśli mamy moduł
Module_test
zdefiniowany w następujący sposób:Teraz dla
include
modułu. Jeśli zdefiniujemy klasęA
w następujący sposób:Wyjście będzie:
M - in module
.Jeśli mamy zamienić linię
include Module_test
zextend Module_test
i ponownie uruchomić kod, otrzymujemy następujący błąd:undefined method 'func' for #<A:instance_num> (NoMethodError)
.Zmiana wywołanie metody
a.func
naA.func
wyjście zmienia się na:M - in module
.Z powyższego wykonania kodu jasno wynika, że gdy jesteśmy
include
modułem, jego metody stają się metodami instancji, a gdy jesteśmyextend
modułem, metody stają się metodami klasy .źródło
Wszystkie pozostałe odpowiedzi są dobre, w tym wskazówka pozwalająca przekopać się przez 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
Jeśli chodzi o przypadki użycia:
Jeśli to moduł ReusableModule w ClassThatIncludes klasy, metody, stałe zajęcia, Submoduły i inne deklaracje dostaje odwoływać.
Jeśli rozszerzysz klasę ClassThatExtends o moduł ReusableModule, wówczas metody i stałe zostaną skopiowane . Oczywiście, jeśli nie jesteś ostrożny, możesz marnować dużo pamięci, dynamicznie powielając definicje.
Jeśli używasz ActiveSupport :: Concern, funkcja .included () pozwala bezpośrednio przepisać klasę włącznie. moduł ClassMethods wewnątrz koncernu zostaje rozszerzony (skopiowany) do klasy włącznie.
źródło
Chciałbym również wyjaśnić mechanizm, który działa. Jeśli nie mam racji, proszę poprawić.
Kiedy używamy
include
, dodajemy link z naszej klasy do modułu, który zawiera niektóre metody.Obiekty nie mają metod, tylko klauzule i moduły. Kiedy więc
a
otrzyma wiadomośćsome_method
, rozpoczyna metodę wyszukiwaniasome_method
wa
klasie własnej, następnie wA
klasie, a następnie wA
modułach klasy, jeśli są dostępne (w odwrotnej kolejności, ostatnie zawarte wygrane).Kiedy używamy
extend
, dodajemy link do modułu w klasie własnej obiektu. Jeśli więc użyjemy A.new.extend (MyMod), dodamy link do naszego modułu do klasy luba'
klasy własnej instancji A. A jeśli użyjemy A.extend (MyMod), dodajemy powiązanie z eigenclass klasy A (obiekty, klasy są również obiektami)A'
.więc ścieżka wyszukiwania metody
a
jest następująca: a => a '=> połączone moduły z klasą' = = A.istnieje również metoda przedpremierowa, która zmienia ścieżkę wyszukiwania:
a => a '=> moduł wstępny do A => A => dołączony moduł do A.
Przepraszam za mój zły angielski.
źródło