我有继承类 Person
的类 Boy
,并包含模块 Bipedal
。 Person
和 Bipedal
都有 #two_legs
的版本。
module Bipedal
def two_legs(name)
puts "#{name} has exactly two limbs used for walking."
end
end
class Person
def two_legs(name)
puts "#{name} has two human legs."
end
end
class Boy < Person
include Bipedal
attr_accessor :name
def initialize(name)
@name = name
end
def two_legs
super(@name)
end
end
因为 Bipedal
模块包含在 Boy
中,所以 Bipedal#two_legs
优先于 Person#two_legs
.当我在 Boy
实例上调用 super
时,模块 Bipedal
优先于父类 Person
。
johnny = Boy.new('Johnny')
johnny.two_legs
# >> "Johnny has exactly two limbs used for walking."
我想在一个地方使用一个版本,在另一个地方使用另一个版本。 Bipedal
还有其他东西,所以我不能注释掉 include Bipedal
。有没有一些标准的方法让 Boy#two_legs
或 super
使用父类版本而不是模块版本,如下所示?
johnny.two_legs
# >> "Johnny has two human legs."
我想到了这个:
Boy.superclass.instance_method(:two_legs).bind(self).call(@name)
代替 super(@name)
工作,但比我预期的要复杂。
同样,问题是,在调用 super
时,是否有一种标准方法可以强制父类优先于模块?
最佳答案
不,没有标准方法强制调用 super
以特定顺序遍历祖先。他们按照预定义的顺序走。看看the documentation on calling methods :
When you send a message, Ruby looks up the method that matches the name of the message for the receiver. Methods are stored in classes and modules so method lookup walks these, not the objects themselves.
Here is the order of method lookup for the receiver's class or module
R
:
- The prepended modules of
R
in reverse order- For a matching method in
R
- The included modules of
R
in reverse orderIf
R
is a class with a superclass, this is repeated withR
's superclass until a method is found.Once a match is found method lookup stops.
由于您的类 Boy
直接包含模块 Bipedal
,并且由于在父类(super class)之前搜索包含的模块,并且一旦找到匹配项就停止搜索,父类(super class) Person
永远不会被检查。
使用refinements时也是如此因为查找总是在检查父类(super class)之前命中包含的模块。
如果您将 include Bipedal
移动到 Person
类中,那么它将按照您期望的方式工作,因为 Boy
不直接包含模块,所以它最终会搜索父类(super class),在那里它会找到定义的方法。
您可能还有其他创造性的方法可以实现此目标,例如您提供的 Boy.superclass...
示例,但您询问是否可以在调用 时更改查找行为super
,根据文档,答案不是。
关于ruby - 让 `super` 通过包含的模块调用父类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53491282/