在另一个模块中包含vs扩展

时间:2014-06-17 06:51:41

标签: ruby module include

为什么下面的代码会返回NoMethodFound错误:

module Mod1
  def print_string
    puts 'hello ruby'
  end
end
module Mod2
  include Mod1
end
Mod2.print_string 

虽然下面的代码运行正常吗?

module Mod1
  def print_string
    puts 'hello ruby'
  end
end
module Mod2
  extend Mod1
end
Mod2.print_string

2 个答案:

答案 0 :(得分:1)

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

  • 如果你致电Klazz.extend(Mod),现在Klazz有Mod的方法(作为课程方法)
  • 如果你致电obj.extend(Mod),现在obj有Mod的方法(作为实例方法),但obj.class的其他实例都没有这些方法。
  • extend是一种公共方法

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

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

然而,模块经常通过猴子修补include方法覆盖 included的行为。这在传统的Rails代码中非常突出。 more details from Yehuda Katz

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

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

当然,the ruby core documentation总是最适合这些事情的地方。 The RubySpec project也是一个很棒的资源,因为它们准确地记录了这些功能。

参考:John

答案 1 :(得分:0)

是的,extend将模块的方法作为类方法添加到调用者,而include将它们添加为实例方法。

一个例子(使用类而不是模块,因为模块不能有实例......)

这有效......

module Mod1
  def print_string
    puts 'hello ruby'
  end
end
class Mod2
  extend Mod1
end
Mod2.print_string

这有效......

module Mod1
  def print_string
    puts 'hello ruby'
  end
end
class Mod2
  include Mod1
end
mod_instance = Mod2.new
mod_instance.print_string