В чем разница между 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!"
751   6  

6 ответов:

то, что вы сказали, верно. Однако есть больше к нему, чем это.

если у вас есть класс Klazz модуль Mod, включая Mod in Klazz дает примеры Klazz доступ к Mod'ы методов. Или вы можете расширить Klazz с Mod дав классKlazz доступ к Mod'ы методов. Но также вы можете расширить произвольный объект с помощью o.extend Mod. В этом случае отдельный объект получает Mod ' ы методы, хотя все остальные объекты с тем же классом, что и o нет.

расширения - добавляет методы и константы указанного модуля в метакласс цели (т. е. одноэлементный класс) например,

  • если вы называете Klazz.extend(Mod), теперь Klazz имеет методы Mod (как методы класса)
  • если вы называете obj.extend(Mod), теперь obj имеет методы Mod (как методы экземпляра), но нет другого экземпляра of obj.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) eigenclass A'.

так путь поиска метода для a выглядит следующим образом: а = а' => подключаемые модули для класса => А.

также есть метод prepend, который изменяет путь поиска:

а = а' => добавляться modulesto А => В => включен модуль

извините за мой плохой английский.

Comments

    Ничего не найдено.