为什么Ruby没有找到调用者类中定义的常量?

时间:2017-10-18 21:03:16

标签: ruby methods programming-languages constants name-lookup

请考虑以下代码:

class MyClass
  def foo_via_method
    foo_method
  end

  def foo_via_constant
    FOO_CONSTANT
  end
end

class SubClass < MyClass
  FOO_CONSTANT = "foo"

  def foo_method
    FOO_CONSTANT
  end
end

这里的两个实例方法表现不同:

sub_class_instance = SubClass.new

### THIS WORKS ###
sub_class_instance.foo_via_method
# => "foo"

### THIS DOESN'T ###
sub_class_instance.foo_via_constant
# NameError: uninitialized constant MyClass::FOO_CONSTANT

引用子类中的方法的版本返回所需的值,但引用子类中的常量的版本会引发错误。所以难题是这样的:为什么使用方法的版本工作但使用常量的版本失败?

1 个答案:

答案 0 :(得分:2)

这是我在实际生产代码中遇到的一个难题。我写了详细解释this blog post中发生了什么。

这里是TLDR:Ruby使用一种更复杂的算法来解析常量而不是方法。常量查找例程的一个阶段涉及查看超类链的定义。这个阶段非常类似于方法查找例程,加深了为什么方法和常量在问题中说明的方式不同的谜团。

解释是两个超类链例程在 start 的位置不同,即哪个类是链的根。

方法查找从self的类开始,其中self是原始方法调用的接收方。在示例中,sub_class_instance是接收器,SubClass是查找开始的位置。 SubClass实现了foo_method,所以一切都很好。

对于常量,Ruby并不是指接收器,因为常量调用不是相对于接收器。相反,常量超类查找以在常量调用发生的词法范围内打开的类开始。在示例中,打开的类是MyClass,因此Ruby开始查找常量 - 并且永远不会找到它。