gpt4 book ai didi

Ruby 类命名空间与模块 : Why do I get NameError with double colons but not module blocks?

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

我正在处理许多预先存在的文件、类和模块,并试图为框架的不同组件提供更好的命名空间。我一直使用模块作为命名空间的一种方式,主要是因为这似乎是标准约定(并且能够“包含”框架的不同部分可能很有用)。

问题是全局命名空间下有大量的类应该存在于模块下。例如,假设有一个类被简单地定义为:

class FirstClass
def meth
puts "HELLO"
end
end

但现在我想在一个模块中有这个类:

使用双冒号:
module Foo; end

class Foo::FirstClass
def meth
puts 'HELLO'
end
end

使用模块 block :
module Foo
class FirstClass
def meth
puts 'HELLO'
end
end

使用双冒号更简洁,也更容易实现,因为我正在更改许多类定义。这两种方式都有效,我认为它们实际上是同一件事,但显然它们不是。与模块 block 相比,双冒号方法似乎导致每个类中的命名空间不同。例如,在“Foo”下面有两个类:

使用模块 block :
module Foo
class FirstClass
def meth
puts 'HELLO'
end
end

class SecondClass
def meth
FirstClass.new.meth
end
end
end

Foo::SecondClass.new.meth

使用双冒号:
module Foo; end

class Foo::FirstClass
def meth
puts 'HELLO'
end
end

class Foo::SecondClass
def meth
FirstClass.new.meth
end
end

Foo::SecondClass.new.meth


该代码在使用模块 block 时有效,但不适用于双冒号。使用双冒号,会引发 NameError 因为它解析 FirstClassFoo::SecondClass::FirstClass (而不是 Foo::FirstClass ),它不存在。

这可以通过包含 Foo 轻松解决。在 SecondClass ,但是为什么默认情况下不这样做呢?

注意:我使用的是 Ruby 2.1.5,我知道它已经过时了,但是我在 repl.it 上使用 ruby​​ 2.5.5p157 得到了相同的结果: https://repl.it/@joep2/Colon-vs-Block-Namespacing

最佳答案

这似乎违反直觉,但 Ruby 中的持续查找是使用当前的 完成的。词法范围 ,即当前的词法嵌套级别(源代码中的位置),而不是语义嵌套级别。

这可以通过检查 Module.nesting 来测试。 ,它打印当前的词法范围:

class Foo::SecondClass
pp Module.nesting # -> [Foo::SecondClass]
end

module Foo
class SecondClass
pp Module.nesting # -> [Foo::SecondClass, Foo]
end
end

由于 Ruby 使用此嵌套级别进行符号查找,这意味着在您尝试查找 FirstClass 的情况下嵌套内 [Foo::SecondClass] , Ruby 不会找到它。

但是,当您尝试在嵌套 [Foo::SecondClass, Foo] 中查找它时,它将找到 FirstClassFoo 下,正如你所料。

为了解决这个问题,你可以这样做:
class Foo::SecondClass
def meth
Foo::FirstClass.new.meth
end
end

现在可以按您的预期工作,因为您为 FirstClass 提供了必要的查找提示。 ,并告诉 Ruby 它在 Foo 内.

关于Ruby 类命名空间与模块 : Why do I get NameError with double colons but not module blocks?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59273879/

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