请考虑以下代码:
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
引用子类中的方法的版本返回所需的值,但引用子类中的常量的版本会引发错误。所以难题是这样的:为什么使用方法的版本工作但使用常量的版本失败?
答案 0 :(得分:2)
这是我在实际生产代码中遇到的一个难题。我写了详细解释this blog post中发生了什么。
这里是TLDR:Ruby使用一种更复杂的算法来解析常量而不是方法。常量查找例程的一个阶段涉及查看超类链的定义。这个阶段非常类似于方法查找例程,加深了为什么方法和常量在问题中说明的方式不同的谜团。
解释是两个超类链例程在 start 的位置不同,即哪个类是链的根。
方法查找从self
的类开始,其中self
是原始方法调用的接收方。在示例中,sub_class_instance
是接收器,SubClass
是查找开始的位置。 SubClass
实现了foo_method
,所以一切都很好。
对于常量,Ruby并不是指接收器,因为常量调用不是相对于接收器。相反,常量超类查找以在常量调用发生的词法范围内打开的类开始。在示例中,打开的类是MyClass
,因此Ruby开始查找常量 - 并且永远不会找到它。