【问题标题】:Ruby: modules extending/including modulesRuby:扩展/包含模块的模块
【发布时间】:2016-02-24 05:42:08
【问题描述】:

我试图更好地理解模块如何扩展和相互包含。

假设我有模块 A

module A
  def learned_from_A
    true
  end
end

A.instance_methods  # [:learned_from_A]

我把它的花样组合到B中:

module B
  extend A
end

B.learned_from_A  # true

我天真地试图给 C 一切 B 拥有:

module C
  extend B
end

C.learned_from_A  # NoMethodError

我想我已经完全理解了这一点。当 B 扩展 A 时,A 的实例方法的副本通过 B 的单例类绑定到 B

B.singleton_methods  # [:learned_from_A]

虽然 :learned_from_A 可在 B 上调用,但它不是 Binstance 方法之一,因此当 C 扩展 B 时,:learned_from_A 不会 复制到 C。 p>


如果 B 改为 包含 A,则 A 的实例方法的副本将包含在 B 自己的实例方法中。

module B
  include A
end

B.instance_methods  # [:learned_from_A]

那么,C可以扩展B,B的所有实例方法(包括:learned_from_A)都会被复制并绑定到C

module C
  extend B
end

C.singleton_methods  # [:learned_from_A]

为了使 :learned_from_AB CB 上都可调用可以扩展并且包含A

module B
  include A
  extend A
end

B.instance_methods   # [:learned_from_A]
B.singleton_methods  # [:learned_from_A]

module C
  extend B
end

C.instance_methods   # []
C.singleton_methods  # [:learned_from_A]

更现实的是,如果我希望 A 的方法可以在 B 上调用,并让 B 定义自己的另一个方法,能够将整个曲目混合到C中,我不能这样做:

module B
  extend A
  include A

  def self.buzz
    true
  end
end

module C
  extend B
end

B 只能共享其实例方法,不能共享其单例方法。因此,要使方法既可在 B 上调用又可共享给其他对象,必须将其定义为实例方法并扩展至 B 本身:

module B
  extend A
  include A

  extend self

  def buzz
    true
  end
end

module C
  extend B
end

将这一切放在一起进行了大量的试验和错误。这是查看正在发生的事情的准确方法吗?

【问题讨论】:

  • 有什么方法可以简化您的问题吗?即使您将其概括为调试了不同场景的要点。
  • 我认为当您在 B 中扩展 A 时,您可能会混淆 self 的范围更改,然后期望 C 将具有 A。您更改了范围。还有可以调用的#prepend。要查看这些范围如何变化,请在您的类上调用 $ancestors 方法。
  • 听起来你想用同名称呼妈妈和女儿:P

标签: ruby module extend


【解决方案1】:

我把它的花招混入B

这句话和你的一般问题让我相信include/extend的概念有一点误解。我提前道歉,因为我不完全理解这个问题。

例如你有这样的模块:

module A
  def a
    puts "a"
  end

  def self.b
    puts "b"
  end
end

如您所见,有两种方法:

  • singleton_methods
  • instance_methods

这是表明它们实际上不同的最简单方法:

A.singleton_methods
=> [:b]
A.instance_methods
=> [:a]
A.a
NoMethodError: undefined method `a' for A:Module
A.b
b
=> nil

如果您简单地使用include A,您就是将其instance 方法添加到当前模块的instance 方法中。当您简单地执行 extend A 时,您将其 instance 方法添加到当前模块的 singleton 方法中。

module B
  include A
end

module C
  extend A
end

B.instance_methods
=> [:a]
B.singleton_methods
=> []
C.instance_methods
=> []
C.singleton_methods
=> [:a]

还有一点要说的是,你可以extend self,但不能include self,因为这没有任何意义,还会引发异常。

module D
  extend self

  def a
    puts "a"
  end

  def self.b
    puts "b"
  end
end

D.singleton_methods
=> [:b, :a]
D.instance_methods
=> [:a]
D.a
a #no error there because we have such singleton method
=> nil

我想这些东西可以帮助你。 StackOverflow 上有很多关于 extend/include 的问题,您可以查看 (example)。

【讨论】:

  • 好答案!有一点不小心被调转了,我想。上述声明之一应为:“当您简单地执行extend A 时,您将其instance 方法添加到当前模块的singleton 方法中。” ("instance" 和 "singleton" 在答案中互换)
【解决方案2】:

以下似乎至少适用于 ABC

module A
  def learned_from_A
    true
  end
end

module B
  prepend A
end

B.learned_from_A  # true

module C
  extend B
end

C.learned_from_A  # true

【讨论】:

    猜你喜欢
    • 2015-04-18
    • 2011-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    • 1970-01-01
    相关资源
    最近更新 更多