В чем разница между include и extend в Ruby?
просто пытаюсь разобраться с метапрограммированием Руби. Mixin / modules всегда удается запутать меня.
включить: смешивает в указанных методах модуля как методы экземпляра в целевом классе
расширения: смешивает в указанных методах модуля как методы класса в целевом классе
так что основная разница только это или больше дракон прячется?
например,
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 ответов:
то, что вы сказали, верно. Однако есть больше к нему, чем это.
если у вас есть класс
KlazzмодульMod, включаяModinKlazzдает примерыKlazzдоступ кMod'ы методов. Или вы можете расширитьKlazzсModдав классKlazzдоступ кMod'ы методов. Но также вы можете расширить произвольный объект с помощьюo.extend Mod. В этом случае отдельный объект получаетMod' ы методы, хотя все остальные объекты с тем же классом, что иoнет.
расширения - добавляет методы и константы указанного модуля в метакласс цели (т. е. одноэлементный класс) например,
- если вы называете
Klazz.extend(Mod), теперь Klazz имеет методы Mod (как методы класса)- если вы называете
obj.extend(Mod), теперь obj имеет методы Mod (как методы экземпляра), но нет другого экземпляра ofobj.classэти методы добавил.extendобщественная методвключить - по умолчанию он смешивается в методах указанного модуля в качестве методов экземпляра в целевом модуле / классе. например,
- если вы называете
class Klazz; include Mod; end;, теперь все экземпляры Klazz имеют доступ к методам Mod (как методы экземпляра)includeявляется частным методом, поскольку он предназначен для вызова из класса/модуля контейнера., очень модули часто переопределить
includeповедение обезьяны-латаниеincludedметод. Это очень заметно в устаревшем коде Rails. более подробная информация от Yehuda Katz.более подробная информация о
include, С его поведением по умолчанию, предполагая, что вы запустили следующий кодclass Klazz include Mod end
- если Mod уже включен в Klazz или один из его предков, оператор include не имеет эффекта
- он также включает в себя константы мод в Клац, пока они не сталкиваются
- это дает Klazz доступ к переменным модуля мод, например
@@fooили@@bar- поднимает ArgumentError, если есть циклические включает
- прикрепляет модуль в качестве непосредственного предка вызывающего абонента (т. е. он добавляет мод в Klazz.предки, но мод не добавляется в цепочку Klazz.надкласс.надкласс.надкласс. Итак, звоню
superв Klazz#foo проверит Mod#foo перед проверкой на foo реального суперкласса Klazz метод. Увидеть RubySpec для деталей.).конечно, основная документация ruby - это всегда лучшее место для этих вещей. проект RubySpec был также фантастический ресурс, потому что они точно документировали функциональность.
Это правильно.
за кулисами, include на самом деле псевдоним для append_features, которые (документы):
реализация Рубина по умолчанию является добавьте константы, методы и модуль переменные данного модуля в модуль, если этот модуль еще не был добавлен в модуль или один из его предков.
все остальные ответы хороши, в том числе наконечник, чтобы копаться в 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
Что касается случаев использования:
Если вы включить модуль ReusableModule в классе Classsthatincludes, методы, константы, классы, подмодули и другие объявления получает ссылки.
Если вы расширения класс Classsthatextends с модулем ReusableModule, то методы и константы получает скопировал. Очевидно, что если вы не будете осторожны, вы можете потратить много памяти на динамическое дублирование определений.
Если вы используете ActiveSupport:: Concern, то.в комплекте() функциональность позволяет переписывать в том числе класса напрямую. модуль ClassMethods внутри концерна получает extended (скопировано)в класс including.
я узнал его раньше, но когда я использую его. Вот в чем разница:
Это не работает, но будет работать, если я определил его как
def page_views(campaign):class UserAction include Calculations def self.page_views(campaign) overall_profit = calculate_campaign_profit(campaign) end endэто работает:
class UserAction extend Calculations def self.page_views(campaign) overall_profit = calculate_campaign_profit(campaign) end end
я также хотел бы объяснить механизм, как он работает. Если я не прав поправьте.
при использовании
includeмы добавляем связь из нашего класса в модуль, который содержит некоторые методы.class A include MyMOd end a = A.new a.some_methodобъекты не имеют методов,только классы и модули. Так что когда
aполучает сообщениеsome_methodон начинает метод поискаsome_methodнаaсобственный класс, то вAкласс, а затем в связанный сAмодули класса, если они есть (в обратный порядок, последний включенный выигрыш).при использовании
extendмы добавляем связь с модулем в собственном классе объекта. Так что если мы используем A. new.extend (MyMod) мы добавляем ссылку на наш модуль к экземпляру класса A eigen илиa'класса. И если мы используем A. extend(MyMod), мы добавляем связь с A(object's, classes are also objects) eigenclassA'.так путь поиска метода для
aвыглядит следующим образом: а = а' => подключаемые модули для класса => А.также есть метод prepend, который изменяет путь поиска:
а = а' => добавляться modulesto А => В => включен модуль
извините за мой плохой английский.
Comments