【问题标题】:Why base class method is being called inside inherited?为什么在继承内部调用基类方法?
【发布时间】:2019-10-21 08:13:08
【问题描述】:

在基类的self.inherited方法中,传递了子类,调用子类的name方法代替调用基类方法。虽然同样的事情如果在其他地方的同一个类上调用相同的方法

class A
 def self.name 
  "a"
 end

 def self.inherited(subclass)
  puts B.hash
  puts B.name
 end
end

class B < A
 def self.name 
  "b"
 end
end

puts B.hash
puts B.name

输出:

1428955046062147697
a
1428955046062147697
b

【问题讨论】:

  • inherited 是在创建子类之前还是之后启动?
  • 有趣的事实:内置的name 方法在任何一种情况下都会返回"B"(因为使用class 关键字时,常量赋值发生在回调之前)。
  • class B &lt; A 之后添加行puts "cat" 并查看它何时显示。

标签: ruby ruby-2.2


【解决方案1】:

这里没有魔法。

当您声明 B 时,事情会按以下顺序发生(粗略地说):

  1. BClass 的一个实例)被创建(它继承了 A 的所有内容)。目前它没有任何具体内容。

  2. A.inherited 钩子被调用。

  3. B 类已打开并处理。只有在这一点上,它才有自己的属性和方法(除了可以在钩子中创建的)。

因此,当 (2) 发生时,唯一可用于 Bname 就是在 A 中定义的那个。

使用以下代码很容易检查:

class A
  def self.name 
    "a"
  end

  def self.inherited(subclass)
    puts "B own methods, point 1: #{subclass.methods(false).join(', ')}"
  end
end

class B < A
  puts "B own methods, point 2: #{self.methods(false).join(', ')}"

  def self.name 
    "b"
  end

  puts "B own methods, point 3: #{self.methods(false).join(', ')}"
end

# B own methods, point 1: 
# B own methods, point 2: 
# B own methods, point 3: name

现在一切都清楚了,对吧?

【讨论】:

  • 似乎需要 post_inherited 方法,否则如果我必须通过一些用户定义的值来处理类,它会变得很麻烦。
  • 你想用无法通过类(重新)打开和常见 Ruby 习语完成的虚构 post_inherited 做什么?
  • @AnuragUniyal,这需要确定继承类的构建何时完成,这可能会出现问题。此外,考虑到在构建子节点时,它可以修改父节点或创建兄弟节点。我不确定这些操作对post_inherited 方法的影响。我预计inherited 的主要原因是构建实例列表。
  • @KonstantinStrukov 它可以通过继承但不优雅来完成,例如你如何制作{name =&gt; subclass}的哈希值
  • @AnuragUniyal 您可以使用inherited 仅构建后代列表,然后按需构建哈希...或者您可以使用与Rais 对.descendants 方法所做的相同的方法' 根本不使用钩子(使用 ObjectSpace 代替)
猜你喜欢
  • 2015-06-05
  • 1970-01-01
  • 2021-10-03
  • 1970-01-01
  • 2012-05-11
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多