【问题标题】:Ruby: Not able to understand why class method is accessible in child classRuby:无法理解为什么在子类中可以访问类方法
【发布时间】:2017-10-19 17:27:47
【问题描述】:

根据 Ruby 方法查找法则,每当我们在对象上调用任何方法时,ruby 都会使用公式 object.class.ancestors 找到该方法。如果这是真的,那么我应该无法使用Child 类常量作为Child.parent 访问父类中定义的父方法,因为Child 类的祖先是[Class, Module, Object, Kernel, BasicObject]。但我可以访问它。谁能告诉我为什么会这样?

class Parent
  def self.parent
    puts "i am parent"
  end
end

class Child < Parent
end

Child.parent # i am parent

我的 jruby 版本是 jruby 1.7.16 (1.9.3p392) 2014-09-25 575b395 on Java HotSpot(TM) 64-Bit Server VM 1.8.0_20-b26 +jit [Windows 8.1-amd64]

【问题讨论】:

  • 您正在使用 jruby 的 old 版本...我不熟悉这个旧版本的怪癖。以下答案适用于任何现代 ruby​​ 版本,包括现代 jruby。

标签: ruby inheritance jruby


【解决方案1】:

您的理解并不完全正确。 object.class.ancestors 没有为您提供将在其中搜索方法的类/模块的完整列表。这是一个反例:

foo = Object.new

def foo.bar
  puts "I'm inside the singleton class"
end

foo.class.ancestors # => [Object, Kernel, BasicObject]
foo.bar # "I'm inside the singleton class"

相反,您必须从对象的单例类开始:

foo.singleton_class.ancestors # => [#<Class:#<Object:0x007fa92c33c610>>, Object, Kernel, BasicObject]
foo.singleton_class.instance_methods.include?(:bar) # => true

知道在调用object.method_name 时,会在某处搜索#method_name

object.singleton_class.ancestors

并且 Ruby 类是常规对象,它仅代表 Child.parent#parent 将在某处寻找

Child.singleton_class.ancestors

神奇之处在于 Ruby 中的类方法在任何方面都没有什么特别之处。它们只是在类的单例类中定义。在您的示例中:

Child.singleton_class.ancestors # => [#<Class:Child>, #<Class:Parent>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

如您所见,Child 的单例类祖先链包括Parent 的单例类。这就是为什么当您调用 Child.parent 时,您实际上是在调用 Parent.parent

【讨论】:

  • Child.singleton_class.ancestors 给了我 [Class, Module, Object, Kernel, BasicObject] 结果,而不是你提到的那个
  • @user2274074,这是不可能的。新建一个irb,复制问题中的代码,然后执行Child.singleton_class.ancestors
  • @user2274074, [Class, Module, Object, Kernel, BasicObject] 是运行Child.class.ancestors 的结果,而不是Child.singleton_class.ancestors
  • 我在执行 Child.singleton_class.ancestors 后编辑了我的问题和附加图片,结果仍然是 [Class, Module, Object, Kernel, BasicObject]
  • 仅供参考,我的 jruby 版本是 jruby 1.7.16 (1.9.3p392) 2014-09-25 575b395 on Java HotSpot(TM) 64-Bit Server VM 1.8.0_20-b26 +jit [Windows 8.1 -amd64]
【解决方案2】:

Child 班级的父母是[Class, Module, Object, Kernel, BasicObject]

不,他们不是:

Child.ancestors
 #=> [Child, Parent, Object, Kernel, BasicObject]

您可以访问Child.parent,因为Child 继承自Parent

但是,为了完整了解类实例可以使用哪些方法,您需要查看singleton_class

Child.singleton_class.ancestors
  #=> [#<Class:Child>, #<Class:Parent>, #<Class:Object>,
       #<Class:BasicObject>, Class, Module, Object,
       Kernel, BasicObject]

【讨论】:

  • 我猜那么在类的情况下查找公式是 Class.ancestors 而在对象的情况下是 object.class.ancestors ???
  • 您输入的是:Child.class.ancestors吗? (如果您在原始问题中包含此信息会很有帮助。)Child 有问题的类,因此您不需要使用Child.class
  • 所谓的“查找公式”非常简单。 klass.ancestors。在这种情况下,您需要klass == Child,而不是klass == Class
  • 如果查找公式是 klass.ancestors 那么为什么我能够使用子类访问“模块”类中定义的方法。例如类模块;定义米;结束;结尾; Child.m ##即使Module不是子类的祖先,这里也能访问方法m
  • @user2274074,类和对象的查找“公式”是相同的。类是对象。只是公式不是anything.class.ancestors而是anything.singleton_class.ancestors
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-14
  • 2015-03-12
  • 1970-01-01
  • 2023-04-05
  • 2019-03-11
相关资源
最近更新 更多