gpt4 book ai didi

ruby - 在 Ruby 中,在 class << self 中定义的方法中,为什么父类上定义的常量不能在没有 self 的情况下访问?

转载 作者:行者123 更新时间:2023-12-04 04:27:03 25 4
gpt4 key购买 nike

我试图更好地理解 Ruby 单例和类继承。我到处读到

def self.method_name; end`
相当于
class << self
def method_name; end
end
但如果这是真的,那么我会期待 print_constant_fails工作,但事实并非如此。这里发生了什么?
class SuperExample
A_CONSTANT = "super example constant"
end

class SubExample < SuperExample
def self.print_constant_works_1
puts A_CONSTANT
end
class << self
def print_constant_works_2
puts self::A_CONSTANT
end
def print_constant_fails
puts A_CONSTANT
end
end
end
pry(main)> SubExample.print_constant_works_1
super example constant

pry(main)> SubExample.print_constant_works_2
super example constant

pry(main)> SubExample.print_constant_fails
NameError: uninitialized constant #<Class:SubExample>::A_CONSTANT
from (pry):13:in `print_constant_fails'

最佳答案

您遇到了一个常见的 Ruby 问题 - 常量查找。
常量查找中最重要的概念是Module.nesting (与方法查找不同,其主要起点是 self )。此方法为您提供当前模块嵌套,Ruby 解释器在解析常量标记时直接使用该嵌套。修改嵌套的唯一方法是使用关键字 classmodule它只包括您使用该关键字的模块和类:

class A
Module.nesting #=> [A]

class B
Module.nesting #=> [A::B, A]
end
end

class A::B
Module.nesting #=> [A::B] sic! no A
end
在元编程中,可以使用 Class.new 动态定义模块或类。或 Module.new - 这不会影响嵌套,并且是一个非常常见的错误原因(啊,还值得一提 - 常量是在 Module.nesting 的第一个模块上定义的):
module A
B = Class.new do
VALUE = 1
end

C = Class.new do
VALUE = 2
end
end

A::B::VALUE #=> uninitialized constant A::B::VALUE
A::VALUE #=> 2
上面的代码将产生两个警告:一个是常量 A::VALUE 的双重初始化,另一个是重新分配常量。
如果它看起来像“我永远不会那样做” - 这也适用于 RSpec.describe 中定义的所有常量(内部调用 Class.new),所以如果你在你的 rspec 测试中定义一个常量,它们肯定是全局的(除非你用 self:: 明确说明要在其中定义的模块)
现在让我们回到您的代码:
class SubExample < SuperExample
puts Module.nesting.inspect #=> [SubExample]

class << self
puts Module.nesting.inspect #=> [#<Class:SubExample>, SubExample]
end
end
解析常量时,解释器首先遍历 Module.nesting 中的所有模块并在该模块中搜索此常量。所以如果嵌套是 [A::B, A]我们正在寻找带有标记 C 的常量,解释器将查找 A::B::C先是 A::C .
但是,在您的示例中,这两种情况都会失败:)。然后解释器开始搜索 Module.nesting 中第一个(也是唯一一个)模块的祖先。 SubrExample.singleton_class.ancestors给你:
[
#<Class:SubExample>,
#<Class:SuperExample>,
#<Class:Object>,
#<Class:BasicObject>,
Class,
Module,
Object,
Kernel,
BasicObject
]
如您所见 - 没有 SuperExample模块,只有它的单例类 - 这就是为什么在 class << self 中不断查找的原因失败( print_constant_fails)。 Subclass的祖先|是:
[
SubExample,
SuperExample,
Object,
Kernel,
BasicObject
]
我们有 SuperExample在那里,所以解释器会设法找到 SuperExample::A_CONSTANT在这个嵌套中。
我们剩下 print_constant_works_2 .这是一个单例类的实例方法,所以 self在这个方法中只是 SubExample .所以,我们正在寻找 SubExample::A_CONSTANT - 不断查找首先搜索 SubExample并且,当它失败时,它的所有祖先,包括 SuperExample .

关于ruby - 在 Ruby 中,在 class << self 中定义的方法中,为什么父类上定义的常量不能在没有 self 的情况下访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68491385/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com