В чем разница между 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
, включая Mod
на Klazz
дает примеры Klazz
доступ к Mod
'ы методов. Или вы можете продлить Klazz
с Mod
дав класс Klazz
доступ к Mod
'ы методов. Но также вы можете расширить произвольный объект с помощью o.extend Mod
. В этом случае индивидуальный объект получает Mod
методы, хотя все остальные объекты с тем же классом, что и o
нет.
расширения - добавляет методы и константы указанного модуля в метакласс цели (т. е. одноэлементный класс) например,
- если вы называете
Klazz.extend(Mod)
, теперь Klazz имеет методы Mod (как методы класса) - если вы называете
obj.extend(Mod)
, теперь obj имеет методы Mod (как методы экземпляра), но нет другого экземпляраobj.class
эти методы добавил. -
extend
общественная метод
включить - по умолчанию он смешивается в методах указанного модуля как методы экземпляра в целевом модуле / классе. например,
- если вы называете
class Klazz; include Mod; end;
, теперь все экземпляры Klazz имеют доступ к методам Mod (как методы экземпляра) -
include
является частным методом, потому что он предназначен для вызова из класса/модуля контейнера.
, очень модули часто переопределить include
поведение обезьяны-латание included
метод. Это очень заметно в коде legacy Rails. больше деталей от Yehuda Katz.
дополнительные сведения о include
, С его поведением по умолчанию, предполагая, что вы выполнили следующий код
class Klazz
include Mod
end
- если Mod уже включен в Klazz или один из его предков, оператор include не имеет никакого эффекта
- он также включает константы Mod в Klazz, пока они не сталкиваются
- это дает Klazz доступ к переменным модуля Mod, например
@@foo
или@@bar
- поднимает ArgumentError, если есть циклические включает
- присоединяет модуль в качестве непосредственного предка вызывающего абонента (т. е. добавляет мод в Klazz.предки, но мод не добавляется в цепочку Klazz.надкласс.надкласс.надкласс. Итак, вызываю
super
в Klazz#foo проверит мод#foo перед проверкой на Foo реального суперкласса Klazz метод. См. RubySpec для деталей.).
конечно, документация по ruby core - это всегда лучшее место для этих вещей. проект RubySpec также был фантастическим ресурсом, потому что они точно документировали функциональность.
Это правильно.
за кулисами, include на самом деле псевдоним для append_features, которые (документы):
реализация Ruby по умолчанию - добавьте константы, методы и модуль переменные данного модуля в модуль, если этот модуль еще не добавлен в модуль или один из его предков.
все остальные ответы хороши, в том числе совет, чтобы копать через 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, методы, константы, классы, подмодули и ссылки на другие объявления.
Если вы расширения class ClassThatExtends с модулем ReusableModule, то методы и константы получает скопировал. Очевидно, что если вы не будете осторожны, вы можете потратить много памяти, динамически дублирования определений.
Если вы используете ActiveSupport::Concern, то .функция included () позволяет переписать класс including напрямую. модуль ClassMethods внутри концерна получает продлен (скопировано)в класс 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
получает mesage some_method
это способ начать поиск some_method
на a
собственный класс, затем в A
класс, а затем в связанном с A
модули класса, если они есть (в обратный порядок, последние включенные выигрыши).
при использовании extend
мы добавляем связь с модулем в собственном классе объекта.
Поэтому, если мы используем A. new.extend (MyMod) мы добавляем связь с нашим модулем в класс экземпляра A или a'
класса.
И если мы используем A. extend (MyMod), мы добавляем связь с(объектами, классы также являются объектами) eigenclass A'
.
Итак, путь поиска метода для a
выглядит следующим образом:
a => a' => связанные модули с A ' class => А.
также есть метод добавления, который изменяет путь поиска:
а = а' => добавляться modulesto А => В => включен модуль
извините за мой плохой английский.