Ruby 何时使用嵌套类和嵌套在模块中的类?

Ruby 何时使用嵌套类和嵌套在模块中的类?,ruby,oop,Ruby,Oop,我非常熟悉何时使用子类和模块,但最近我看到了这样的嵌套类: class Foo class Bar # do some useful things end end 以及嵌套在模块中的类,如: module Baz class Quux # more code end end 要么是文档和文章太少,要么是我没有受过足够的教育去寻找合适的搜索词,但我似乎找不到关于这个主题的太多信息 有人能提供一些例子或链接,说明为什么/何时会使用这些技术吗?你可能想用它将你的类分

我非常熟悉何时使用子类和模块,但最近我看到了这样的嵌套类:

class Foo
  class Bar
    # do some useful things
  end
end
以及嵌套在模块中的类,如:

module Baz
  class Quux
    # more code
  end
end
要么是文档和文章太少,要么是我没有受过足够的教育去寻找合适的搜索词,但我似乎找不到关于这个主题的太多信息


有人能提供一些例子或链接,说明为什么/何时会使用这些技术吗?

你可能想用它将你的类分组成一个模块。有点像命名空间

例如,使用名称空间来实现这一点:

Twitter::Client.new

Twitter::Search.new
因此
Client
Search
类都位于
Twitter
模块下

如果您想检查源代码,可以找到这两个类的代码

希望这有帮助

其他OOP语言都有,如果不绑定到上层类,就无法实例化这些语言。比如在Java中

class Car {
    class Wheel { }
}
只有
Car
类中的方法才能创建
Wheel
s

鲁比没有那种行为

红宝石色

class Car
  class Wheel
  end
end
不同于

class Car
end

class Wheel
end
module ActionMailer
  class Base
  end
end
仅在类别
车轮
汽车::车轮
的名称中。这种名称上的差异可以让程序员明白,
Car::Wheel
类只能表示一个车轮,而不是普通的车轮。在Ruby中嵌套类定义是一个优先考虑的问题,但它的目的是更有力地执行两个类之间的契约,并在这样做时传递更多关于它们及其使用的信息

但是对于Ruby解释器来说,这只是名称上的不同

至于您的第二个观察,嵌套在模块内部的类通常用于为类命名名称空间。例如:

module ActiveRecord
  class Base
  end
end
不同于

class Car
end

class Wheel
end
module ActionMailer
  class Base
  end
end

尽管这不是嵌套在模块内部的类的唯一用法,但它通常是最常见的。

在Ruby中,定义嵌套类类似于在模块中定义类。它实际上并不强制类之间建立关联,它只是为常量创建一个名称空间。(类和模块名称是常量。)

被接受的答案在任何方面都不正确。在下面的示例中,我创建了一个词汇封闭类的实例,而封闭类的实例不存在

class A; class B; end; end
A::B.new
这些优点与模块的优点相同:封装、只在一个地方使用分组代码,以及将代码放在离使用位置更近的地方。一个大型项目可能有一个外部模块,它在每个源文件中反复出现,并包含许多类定义。当各种框架和库代码都这样做时,它们只向顶层贡献一个名称,从而减少了冲突的机会。平淡无奇,但这就是它们被使用的原因

使用类而不是模块来定义外部名称空间在单文件程序或脚本中可能是有意义的,或者如果您已经使用顶级类进行某些操作,或者如果您实际上打算添加代码以真正的内部类样式将类链接在一起。Ruby没有内部类,但没有任何东西可以阻止您在代码中创建相同的行为。从内部对象引用外部对象仍然需要从外部对象的实例中插入点,但是嵌套类将表明这是您可能正在做的事情。一个精心模块化的程序可能总是首先创建封闭类,并且可以合理地使用嵌套类或内部类对它们进行分解。您不能在模块上调用
new

您甚至可以在脚本中使用通用模式,在脚本中名称空间不是非常需要,只是为了好玩和练习

#!/usr/bin/env ruby

class A
  class Realwork_A
    ...
  end
  class Realwork_B
    ...
  end

  def run
    ...
  end
  
  self
end.new.run

除了前面的答案:Ruby中的模块是一个类

$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object

Ruby 2.5之前版本中的嵌套类和嵌套模块之间还有另一个区别,我觉得这里必须提到其他答案未能涵盖。这是查找过程。

简而言之:由于Ruby 2.5之前的顶级常量查找,如果使用嵌套类,Ruby可能会在错误的位置(尤其是在
对象中)查找嵌套类。

在Ruby 2.5之前的版本中:
嵌套类结构: 假设您有一个类
X
,带有嵌套类
Y
,或
X::Y
。然后有一个顶级类,名为
Y
。如果未加载
X::Y
,则调用
X::Y


X
中没有找到
Y
,Ruby将尝试在
X
的祖先中查找它。由于
X
是一个类而不是一个模块,因此它有祖先,其中包括
[对象、内核、基本对象]
。因此,它尝试在
对象
中查找
Y
,并成功地找到了它。

但它是顶级
Y
,而不是
X::Y
。 您将收到以下警告:

warning: toplevel constant Y referenced by X::Y

嵌套模块结构: 假设在前面的示例中,
X
是一个模块而不是一个类。

一个模块只有自己作为祖先:
X。祖先将产生
[X]


在这种情况下,Ruby将无法在
X
的祖先之一中查找
Y
,并将抛出
NameError
。Rails(或任何其他自动加载的框架)将尝试在此之后加载
X::Y


有关更多信息,请参阅本文:

Ruby 2.5中的

顶级常量查找已删除。
您可以使用嵌套类而不用担心遇到此错误。

@rubyprince,我不确定您在
Car.new
Car::Wheel.new
之间建立关系的意思。在Ruby中初始化
Car::Wheel
对象时,您肯定不需要初始化
Car
对象,但是