Ruby 刚看到有贴说 class A 和 module A::B 的疑问

yxmmrwx · 2025年01月18日 · 最后由 xiaoronglv 回复于 2025年01月28日 · 365 次阅读

class A end

module A::B end

从测试效果来看 A 是类 A::B 是模块,这里的 A::B 是一个完整的名字,不能把 A::B 分解成 A 和 B 来看,应该是为了方面名字叫空间的管理的识别用, 跟 C++ module A.B.C 的用意一样

所以 class A 和 module A::B 没有任何关系?

是我搞错了。定义了一个类 A,这个 A 它既是一个 Class 也是一个 Module,不矛盾,因为 Class 的 superclass 是 Module。

又再测试一下,发现前面讲的 A::B 是一个完整的名字,是错的,因为能访问到单独的 B, p A.ancestors #=>[A, Object, Kernel, BasicObject] p A::B.ancestors #=>[A::B] p A.constants[0] #=>:B p A.constants[0].class #=>Symbol 能看到的 A 既是类也是模块,再深入看到上面的结果又迷糊了

看一下这样想是不是更好理解一些:

lz 的例子是

class A end
module A::B end

如果不执行class A end,直接执行module A::B end,程序会报错uninitialized constant A 未初始化常量 A

其实 module A::B end,按照例子想要的效果,也可以用嵌套方式写成

class A
  module B
  end
end

这样定义后,即会有class类型的A常量,又会有module类型的B常量,也就是说B实际上是class A的 submodule

那么为什么不执行class A end,直接执行module A::B end会报错;以及 A::B 是不是一个完整的名字这个问题,我认为只要明白 ruby 中::语法的作用就会清晰很多了

::语法的一个用途是访问常量,当执行module A::B end时,实际上在访问 A 常量下的 B 常量,这时候B常量会作为一个 module 来声明,其作用域自然是被访问的 A 常量,报错的原因即是因为 A 常量没被定义 也就是说 A::B 称为完整并不合适,A 和 B 是有从属关系的,即上面通过嵌套方式写的代码

在写代码的时候,为了避开 module 名字和 class 名字的冲突,一般会把 module 的名字变为复数。

比如

  • class 叫 Employee
  • module 叫 Employees。module 下就可以定义各种
    • job
    • lib
    • rake task

这样就能避开冲突。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号