Ruby中包含和扩展有什么区别?

Gis*_*shu 397 ruby module include extend

刚刚开始关注Ruby元编程.mixin/modules总是让我困惑.

  • 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!"
Run Code Online (Sandbox Code Playgroud)

Joh*_*hat 310

extend - 将指定模块的方法和常量添加到目标的元类(即单例类),例如

  • 如果你打电话Klazz.extend(Mod),现在Klazz有Mod的方法(作为类方法)
  • 如果你调用obj.extend(Mod),现在obj有Mod的方法(作为实例方法),但没有其他实例obj.class添加了这些方法.
  • extend 是一种公共方法

include - 默认情况下,它将指定模块的方法混合为目标模块/类中的实例方法.例如

  • 如果你打电话class Klazz; include Mod; end;,现在Klazz的所有实例都可以访问Mod的方法(作为实例方法)
  • include 是一个私有方法,因为它旨在从容器类/模块中调用.

但是,模块经常通过修补方法来覆盖其 include行为included.这在传统的Rails代码中非常突出.来自Yehuda Katz的更多细节.

include假设您运行以下代码,有关其默认行为的更多详细信息

class Klazz
  include Mod
end
Run Code Online (Sandbox Code Playgroud)
  • 如果Mod已包含在Klazz或其祖先之一中,则include语句无效
  • 它还包括Mod在Klazz中的常量,只要它们不冲突
  • 它使Klazz可以访问Mod的模块变量,例如@@foo@@bar
  • 如果存在循环包含则引发ArgumentError
  • 将模块作为调用者的直接祖先附加(即它将Mod添加到Klazz.ancestors,但是Mod没有添加到Klazz.superclass.superclass.superclass的链中.因此,调用superKlazz #foo将在检查之前检查Mod#foo Klazz的真正超类的foo方法.有关详细信息,请参阅RubySpec.).

当然,ruby核心文档总是最适合这些事情的地方.RubySpec项目也是一个很棒的资源,因为他们精确地记录了这些功能.

  • 我知道这是一个相当古老的帖子,但回复的清晰度不能阻止我评论.非常感谢您的解释. (18认同)
  • @anwar 显然,但现在我可以发表评论,并且我设法再次找到了这篇文章。它可以在这里找到:http://aaronlasseigne.com/2012/01/17/explaining-include-and-extend/,我仍然认为模式使理解更容易 (2认同)
  • 此响应的最大优点是“extend”如何将方法应用为类*或*实例方法,具体取决于利用率。`Klass.extend` = 类方法,`objekt.extend` = 实例方法。我总是(错误地)假设类方法来自“extend”,实例来自“include”。 (2认同)

dom*_*ell 240

你所说的是对的.然而,除此之外还有更多.

如果你有一个类Klazz和模块Mod,包括Modin Klazz给出了Klazz访问Mod方法的实例.或者你可以Klazz通过Mod赋予 Klazz访问Mod方法来扩展.但是你也可以扩展一个任意对象o.extend Mod.在这种情况下,单个对象获取Mod方法,即使具有相同类的所有其他对象o也没有.


Tob*_*ede 14

那是对的.

在幕后,include实际上是append_features的别名,(来自文档):

Ruby的默认实现是将此模块的常量,方法和模块变量添加到aModule(如果此模块尚未添加到aModule或其祖先之一).


Chi*_*tan 9

当您将include一个模块放入一个类中时,模块方法将作为实例方法导入。

但是,当您extend将模块放入类时,模块方法将作为类方法导入。

例如,如果我们有一个Module_test定义如下的模块:

module Module_test
  def func
    puts "M - in module"
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,对于include模块。如果我们定义类A如下:

class A
  include Module_test
end

a = A.new
a.func
Run Code Online (Sandbox Code Playgroud)

输出将是:M - in module

如果我们更换线include Module_testextend Module_test并再次运行该代码,我们收到以下错误:undefined method 'func' for #<A:instance_num> (NoMethodError)

将方法调用更改a.funcA.func,输出更改为:M - in module

从上面的代码执行可以看出,当我们include是一个模块时,它的方法就变成了实例方法,当我们extend成为一个模块时,它的方法就变成了类方法