简体   繁体   English

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

[英]Why doesn't Ruby find constants defined in the caller's class?

Consider the following code: 考虑以下代码:

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

The two instance methods here behave differently: 这两个实例方法的行为有所不同:

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

The version that refers to a method in the subclass returns the desired value, but the version that refers to a constant in subclass throws an error. 引用子类中的方法的版本将返回所需的值,但是引用子类中的常量的版本将引发错误。 So the puzzle is this: Why does the version that uses a method work but the version that uses the constant fail? 那么难题就在于:为什么使用方法的版本可以工作,而使用常量的版本却会失败?

This was a puzzle that I encountered in real production code. 这是我在实际生产代码中遇到的难题。 I wrote up a detailed explanation of what's going on in this blog post . 我在此博客文章中写了详细的解释。

Here's the TLDR: Ruby uses a much more complex algorithm for resolving constants than it does for methods. 这是TLDR:与方法相比,Ruby使用更复杂的算法来解析常量。 One phase of the constant lookup routine involves looking through the superclass chain for the definition. 常量查找例程的一个阶段涉及通过超类链查找定义。 This phase looks very much like the method lookup routine, deepening the mystery of why methods and constants differ in the way illustrated in the question. 该阶段非常类似于方法查找例程,这加深了为什么方法和常量在问题中说明的方式不同的谜。

The explanation is that the two superclass chain routines differ in where they start , ie which class is the root of the chain. 解释是,这两个超类链例程的起始位置不同,即哪个类是链的根。

Method lookup starts with self 's class, where self is the receiver of the original method call. 方法查找从self的类开始,其中self是原始方法调用的接收者。 In the example, sub_class_instance is the receiver and SubClass is where the lookup starts. 在该示例中, sub_class_instance是接收方,而SubClass是查找开始的地方。 SubClass implements foo_method , so all is well. SubClass实现foo_method ,所以一切都很好。

For constants, Ruby doesn't refer to a receiver, because constant invocations aren't relative to a receiver. 对于常量,Ruby不引用接收器,因为常量调用与接收器无关。 Instead, constant superclass lookup begins with the class that's open at the lexical scope where the constant invocation occurs. 相反,常量超类查找始于在发生常量调用的词法范围内打开的类。 In the example, the class that's open is MyClass , so thats where Ruby starts to looks for the constant—and never finds it. 在示例中,打开的类是MyClass ,因此Ruby开始在其中查找常量,而从没有找到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM