【发布时间】:2023-04-01 14:57:02
【问题描述】:
我正在处理大量预先存在的文件、类和模块,并试图为框架的不同组件提供更好的命名空间。我一直使用模块作为命名空间的一种方式,主要是因为这似乎是标准约定(并且能够“包含”框架的不同部分可能很有用)。
问题是全局命名空间下有大量的类应该存在于模块下。例如,假设有一个类被简单地定义为:
class FirstClass
def meth
puts "HELLO"
end
end
但现在我想在一个模块中包含这个类:
使用双冒号:
module Foo; end
class Foo::FirstClass
def meth
puts 'HELLO'
end
end
使用模块块:
module Foo
class FirstClass
def meth
puts 'HELLO'
end
end
使用双冒号更简洁,也更容易实现,因为我正在更改许多类定义。这两种方式都有效,我认为它们实际上是同一件事,但显然它们不是。与模块块相比,双冒号方法似乎导致每个类中的命名空间不同。例如,在“Foo”下面有两个类:
使用模块块:
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
代码在使用模块块时有效,但不适用于双冒号。使用双冒号会引发 NameError,因为它将 FirstClass 解析为不存在的 Foo::SecondClass::FirstClass(而不是 Foo::FirstClass)。
这可以通过在SecondClass 中包含Foo 轻松解决,但为什么默认情况下不这样做呢?
注意:我使用的是 Ruby 2.1.5,我知道它已经过时了,但我在 repl.it 上使用 ruby 2.5.5p157 得到了相同的结果:https://repl.it/@joep2/Colon-vs-Block-Namespacing
【问题讨论】:
-
如果在“模块块”的情况下,插入行
puts "constants = #{constants}"作为模块定义的最后一行,您将看到显示constants = [:SecondClass, :FirstClass]。这告诉您,在模块定义中,您可以引用不带双冒号的类。也就是说,FirstClass.new.meth和Foo::FirstClass.new.meth一样(也可以使用)。 -
@CarySwoveland 我知道
Foo::FirstClass.new.meth语法,但我想避免这样做,因为我正在修改预先存在的代码,因此更改对 FirstClass 的每个引用(以前是顶级- level class) 会有点费时,而且看起来不是很干净。现在,我只是将include Foo放在class Foo::FirstClass的下面以及Foo 中的所有其他类中。
标签: ruby