刚刚开始关注Ruby元编程。 mixin / modules老是让我困惑。 html
那么主要区别在于这仍是潜伏着更大的龙? 例如 git
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!"
那是对的。 github
在幕后,include其实是append_features的别名,(来自文档): 编程
Ruby的默认实现是将此模块的常量,方法和模块变量添加到aModule(若是此模块还没有添加到aModule或其祖先之一)。 ruby
你所说的是对的。 然而,除此以外还有更多。 app
若是你有一个类Klazz
和模块Mod
,包括Klazz
Mod
, Klazz
让Klazz
访问Mod
的方法。 或者您可使用Mod
扩展Klazz
,使Klazz
类 Klazz
访问Mod
的方法。 可是你也能够用o.extend Mod
扩展一个任意对象。 在这种状况下,单个对象获取Mod
的方法,即便与o
具备相同类的全部其余对象也没有。 spa
我还想解释它的做用机制。 若是我不对,请纠正。 .net
当咱们使用include
咱们将从类中添加一个连接到一个包含一些方法的模块。 code
class A include MyMOd end a = A.new a.some_method
对象没有方法,只有clases和模块。 因此当a
接收消息some_method
它开始在a
特征类中搜索方法some_method
,而后在A
类中而后连接到A
类模块,若是有一些(以相反顺序,最后包括胜利)。 htm
当咱们使用extend
咱们将对象的特征类中的模块添加连接。 所以,若是咱们使用A.new.extend(MyMod),咱们将模块的连接添加到A的实例特征类或a'
类。 若是咱们使用A.extend(MyMod),咱们将添加连接到A(对象,类也是对象)本征类A'
。
所以对于方法查找路径a
是以下:a =>一个“=>连接的模块为”类=> A.
还有一个更改查找路径的prepend方法:
a => a'=>前置模块A => A =>包含模块到A
对不起,个人英语很差。
extend - 将指定模块的方法和常量添加到目标的元类(即单例类),例如
Klazz.extend(Mod)
,如今Klazz有Mod的方法(做为类方法) obj.extend(Mod)
,如今obj有Mod的方法(做为实例方法),但没有其余obj.class
实例添加了这些方法。 extend
是一种公共方法 include - 默认状况下,它将指定模块的方法混合为目标模块/类中的实例方法。 例如
class Klazz; include Mod; end;
class Klazz; include Mod; end;
,如今Klazz的全部实例均可以访问Mod的方法(做为实例方法) include
是一个私有方法,由于它是从容器类/模块中调用的。 可是 ,模块常常经过猴子修补included
方法来覆盖 include
的行为。 这在传统的Rails代码中很是突出。 来自Yehuda Katz的更多细节 。
假设您运行如下代码,有关include
其默认行为的更多详细信息
class Klazz include Mod end
@@foo
或@@bar
super
将检查Mod#foo以前检查Klazz真正的超类的foo方法。有关详细信息,请参阅RubySpec。)。 固然, ruby核心文档老是最适合这些事情的地方。 RubySpec项目也是一个很棒的资源,由于他们精确地记录了这些功能。
#include
RubySpec rubydoc #included
RubySpec rubydoc #extend
RubySpec rubydoc #extended
RubySpec rubydoc #extend_object
RubySpec rubydoc #append_features
RubySpec rubydoc 全部其余答案都很好,包括挖掘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
至于用例:
若是在ClassThatIncludes类中包含模块ReusableModule,则会引用方法,常量,类,子模块和其余声明。
若是使用模块ReusableModule 扩展类ClassThatExtends,则会复制方法和常量。 显然,若是你不当心,你能够经过动态复制定义来浪费大量内存。
若是使用ActiveSupport :: Concern,则.included()功能容许您直接重写包含类。 关注内的模块ClassMethods被扩展 (复制)到包含类中。