Ruby: 模块扩展/包含模块

16

我希望您能够帮助翻译涉及IT技术的文本。下面是需要翻译的内容:

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

假设我有一个名为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上调用,但它不是B的一个实例方法,所以当C扩展B时,:learned_from_A不会被复制到C


如果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_ABC上都可调用,B可以扩展并包含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

在将所有内容整合在一起的过程中,进行了相当多的试错。这种方式能准确地展示正在发生的事情吗?


有没有简化你的问题的方式?即使您将其概述并调试出不同的场景。 - onebree
我认为你可能会混淆在B内部扩展A时self的作用域变化,然后期望C将具有A。你改变了作用域。还有可以调用的#prepend。要查看这些作用域如何更改,请在您的类上调用$ancestors方法。 - R.J. Robinson
1
听起来你想用同一个名字称呼妈妈和女儿 :P - Vasu Adari
2个回答

9
我可以翻译该内容。这是关于编程的内容,作者认为在“include”和“extend”这两个概念上有些误解。作者不理解问题的全部内容。以下是需要翻译的原文:

I mix its bag of tricks into B

例如,你有这样一个模块:

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,则将其实例方法添加到当前模块的实例方法中。当您简单地执行extend A时,则将其实例方法添加到当前模块的单例方法中。
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

我猜这些东西可能会对你有所帮助。关于extend/include的问题,StackOverflow上有很多你可以参考(例子)。


2
好的回答!我觉得有一个比特被意外地交换了。上面的语句之一应该是:“当你简单地执行extend A时,你正在将其实例方法添加到当前模块的单例方法中。”(答案中的“实例”和“单例”位置对调了) - ivan

0

以下代码至少对于 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接