Jaka jest różnica między include i extend w Ruby?
Zaczynam myśleć o Metaprogramowaniu Ruby. Mixin / modules zawsze udaje mi się zmylić.
- include : mixuje w określonych metodach modułu jako metody instancji w klasie docelowej
- extend : miesza się w określonych metodach modułu jako metody klasy w klasie docelowej
więc czy główna różnica to tylko to, czy czy czyhający większy smok? np.
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!"
6 answers
To, co powiedziałeś, jest poprawne. Jednak jest w tym coś więcej.
Jeśli masz klasę Klazz
i moduł Mod
, w tym Mod
w Klazz
daje instancje Klazz
dostęp do metod Mod
. Możesz też rozszerzyć Klazz
z Mod
dając klasę Klazz
dostęp do metod Mod
. Ale możesz również rozszerzyć dowolny obiekt za pomocą o.extend Mod
. W tym przypadku pojedynczy obiekt otrzymuje metody Mod
, mimo że wszystkie inne obiekty z tą samą klasą co o
nie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-07 02:32:47
Extend - dodaje metody i stałe podanego modułu do metaklasy celu (tj. klasy singleton) np.
- Jeśli wywołasz
Klazz.extend(Mod)
, Teraz Klazz ma metody Mod (jako metody klasowe) - Jeśli wywołasz
obj.extend(Mod)
, Teraz obj ma metody Mod( jako metody instancji), ale żadna inna instancjaobj.class
nie ma tych metod dodanych. -
extend
jest metodą publiczną
Include - domyślnie miesza się w podanym module metody jako metody instancji w docelowym module / klasie. np.
- Jeśli wywołasz
class Klazz; include Mod; end;
, Teraz wszystkie instancje Klazz mają dostęp do metod Moda (jako metody instancji) - {[6] } jest metodą prywatną, ponieważ jest przeznaczona do wywołania z poziomu klasy/modułu kontenera.
Jednak, Moduły bardzo często nadpisują include
's zachowanie przez małpę-łatanie metodą included
. Jest to bardzo widoczne w kodzie legacy Rails. więcej szczegółów od Yehuda Katz .
Dalsze szczegóły na temat include
, z domyślnym zachowaniem, zakładając, że uruchomiłeś następujący kod
class Klazz
include Mod
end
- Jeśli Mod jest już zawarty w Klazz, lub jeden z jego przodków, oświadczenie include nie ma wpływu
- zawiera również stałe Mod w Klazz, o ile nie kolidują ze sobą
- daje dostęp do zmiennych modułu Mod, np.
@@foo
lub@@bar
- podnosi ArgumentError jeśli istnieją cykliczne zawiera
- dołącza moduł jako najbliższy przodek wywołującego (tzn. dodaje Mod do Klazz.przodków, ale Mod nie jest dodawany do łańcucha Klazz.superklasa.superklasa.superklasa. Tak więc wywołanie
super
W Klazz#foo sprawdzi Mod#foo przed sprawdzeniem do prawdziwej metody Klazz 's superclass' s foo. Szczegóły w rubyspec.).
Oczywiście, dokumentacja ruby core jest zawsze najlepszym miejscem na takie rzeczy. projekt RubySpec był również fantastyczny zasób, ponieważ dokładnie udokumentowali funkcjonalność.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-22 21:53:23
Zgadza się.
Za kulisami, include jest w rzeczywistości aliasem dla append_features , który (z dokumentów):
Domyślną implementacją Ruby jest dodaj stałe, metody i moduł zmienne tego modułu do aModule jeżeli ten moduł nie został jeszcze dodany do aModule lub jednego z jej przodków.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-01 08:08:30
Wszystkie inne odpowiedzi są dobre, w tym wskazówka do kopania 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
Co do przypadków użycia:
Jeśli dołączysz Moduł ReusableModule do klasy ClassThatIncludes, metody, stałe, klasy, podmodule i inne deklaracje zostaną odwołane.
Jeśli rozszerzysz klasę ClassThatExtends z modułem ReusableModule, wtedy metody i stałe zostaną skopiowane . Oczywiście, jeśli nie jesteś ostrożny, możesz zmarnować dużo pamięci przez dynamiczne powielanie definicji.
Jeśli używasz Activesupport:: Concern, the .funkcja included () umożliwia bezpośrednie przepisanie klasy including. moduł ClassMethods wewnątrz problemu otrzymuje rozszerzone (skopiowane) do klasy including.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-22 21:02:06
Nauczyłem się go wcześniej, ale doceniam to, gdy go używam. Oto różnica:
To nie działa, ale działałoby, gdybym zdefiniował to jako def page_views(campaign)
:
class UserAction
include Calculations
def self.page_views(campaign)
overall_profit = calculate_campaign_profit(campaign)
end
end
To działa:
class UserAction
extend Calculations
def self.page_views(campaign)
overall_profit = calculate_campaign_profit(campaign)
end
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-02 12:21:13
Chciałbym również wyjaśnić mechanizm, jak to działa. Jeśli nie mam racji, proszę poprawić.
Kiedy używamy include
dodajemy link z naszej klasy do modułu, który zawiera pewne metody.
class A
include MyMOd
end
a = A.new
a.some_method
Obiekty nie mają metod, tylko klasy i moduły.
Tak więc, gdy a
otrzymuje mesage some_method
, rozpoczyna wyszukiwanie metody some_method
w klasie eigen a
, Następnie w klasie A
, a następnie w modułach klasy linked to A
, jeśli są jakieś (w odwrotnej kolejności, ostatnio włączone zwycięstwa).
Kiedy używamy extend
dodajemy linkowanie do modułu w klasie eigen obiektu.
Więc jeśli użyjemy A. new.extend (MyMod) dodajemy link do naszego modułu do instancji klasy eigen lub klasy a'
.
I jeśli użyjemy A. extend(MyMod) dodajemy linkowanie do a (object ' s, klasy są również obiektami) eigenclass A'
.
Więc ścieżka wyszukiwania metody dla a
jest następująca:
a= > A' = > połączone moduły do A ' class = > A.
Istnieje również metoda prepend, która zmienia lookup ścieżka:
A => a' = > dołączony moduł do A => a = > dołączony moduł do a
Przepraszam za zły angielski.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-27 12:11:02