Ruby: 模块 extending/including 个模块

Ruby: modules extending/including modules

我正在努力更好地理解模块如何相互扩展和包含。

说我有模块 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 的单例 [=128] 绑定到 B =]:

B.singleton_methods  # [:learned_from_A]

虽然 :learned_from_A 可在 B 上调用,但它不是 B[=86 之一=] 的 instance 方法,所以当 C 扩展 B, :learned_from_A 而不是 复制到 C.


如果 B 改为 included 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 C, B 可以扩展 and 包括 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

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

I mix its bag of tricks into 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

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

以下似乎至少适用于 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