Ruby中的include和extend有什么区别?
只是让我的头在Ruby元编程。 mixin /模块总是会让我困惑。Ruby中的include和extend有什么区别?
- 包括:在指定的模块的方法混合在目标类
- 实例方法延伸:在指定的模块的方法混合在目标类类方法
那么这个主要区别就在这个还是一个更大的潜伏龙? 例如
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!"
你说的是对的。然而,除此之外还有更多。
如果你有一个类Klazz
和模块Mod
,包括Klazz
Mod
给出Klazz
访问Mod
的方法实例。或者,您可以使用Mod
扩展Klazz
,使类Klazz
可以访问Mod
的方法。但是你也可以用o.extend Mod
来扩展一个任意的对象。在这种情况下,即使所有其他与o
同类的对象都没有,单个对象也会获得Mod
的方法。
这是正确的。
在幕后,包括实际上是别名append_features,这(从文档):
Ruby的默认实现是 添加常数,方法和模块该模块的 变量到aModule如果 该模块尚未将 添加到aModule或其祖先之一。
extend - 将指定模块的方法和常量添加到目标的元类(即单例类) 例如,
- 如果你打电话
Klazz.extend(Mod)
,现在Klazz有国防部的方法(类方法) - 如果你打电话
obj.extend(Mod)
,现在OBJ有国防部的方法(例如方法),但的obj.class
没有其他的实例有那些方法添加。 -
extend
是一个公共方法
包括 - 默认情况下,它在指定的模块的方法作为目标模块/类的实例方法混合。 例如
- 如果你打电话
class Klazz; include Mod; end;
,现在Klazz的所有实例访问国防部的方法(例如方法) -
include
是一个私有方法,因为它旨在从容器类/模块中调用。
然而,模块非常经常由猴子修补included
方法倍率include
的行为。这在传统的Rails代码中非常突出。 more details from Yehuda Katz。
约include
,其默认行为的更多细节,假设你运行下面的代码
class Klazz
include Mod
end
- 如果国防部已经包含在Klazz,或其祖先之一,包括语句没有效果
- 它还包括Mod在Klazz中的常量,只要它们不冲突
- 它可以让Klazz访问Mod的模块变量,例如
@@foo
或@@bar
- 引发ArgumentError如果有环状包括
- 将已模块作为呼叫者的直接祖先(即它增加了国防部到Klazz.ancestors,但国防部不被添加到Klazz.superclass.superclass.superclass的链所以在Klazz#foo中调用
super
将在检查Klazz的真正超类的foo方法之前检查Mod#foo,详情请参阅RubySpec。)。
当然,the ruby core documentation永远是这些事情的最佳去处。 The RubySpec project也是一个很好的资源,因为他们精确地记录了功能。
我知道这是很旧的帖子,但答复的清晰度无法阻止我评论。非常感谢一个很好的解释。 – MohamedSanaulla 2011-12-25 15:30:07
所有其他的答案是好的,包括端通过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将扩展为(复制)到包含类中。
我以前学过它,但在使用它时非常感谢。这里的区别是:
这并不工作,但会工作,如果我把它定义为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的实例特征类或a'
类。 如果我们使用A.extend(MyMod),我们正在向A添加链接(对象的类也是对象)本征类A'
。
所以对于a
方法查找路径如下: 一个=>一个“=>链接的模块为”类=> A.
也有一个前置方法,其改变查找路径:
a => a'=>前置模块A => A =>包含模块至A
对不起,我的英文不好。
查看这个链接:http://juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby/ – Donato 2016-12-20 17:53:00