[英]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.