Answers:
其他OOP语言具有内部类,这些内部类必须绑定到上层类才能实例化。例如,在Java中,
class Car {
class Wheel { }
}
只有Car
类中的方法才能创建Wheel
。
Ruby没有这种行为。
在Ruby中
class Car
class Wheel
end
end
不同于
class Car
end
class Wheel
end
仅以类Wheel
vs. 的名义Car::Wheel
。名称上的这种差异可以向程序员表明,Car::Wheel
该类只能代表一个车轮,而不是一个普通的车轮。在Ruby中嵌套类定义是一个优先事项,但在某种意义上说,它可以更严格地在两个类之间强制执行契约,并以此传达有关它们及其用途的更多信息。
但是对于Ruby解释器而言,这只是名称上的不同。
关于第二个观察,嵌套在模块内部的类通常用于为这些类命名空间。例如:
module ActiveRecord
class Base
end
end
不同于
module ActionMailer
class Base
end
end
尽管这不是嵌套在模块内部的类的唯一用途,但通常是最常见的。
Car
和之间绝对没有任何关系Car::Wheel
。模块(以及类)只是常量的名称空间,在Ruby中没有嵌套类或嵌套模块之类的东西。
Car::Wheel.new
。繁荣。我刚刚构造了一个Wheel
不嵌套在Car
对象内部的对象。
在Ruby中,定义嵌套类类似于在模块中定义类。它实际上并不强制类之间的关联,而只是为常量创建一个名称空间。(类和模块名称是常量。)
公认的答案对任何事情都不正确。1在下面的示例中,我创建了一个词法包围类的实例,而该类没有一个实例。
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
B
是不是内部类A
。该常量 B
在类内部命名空间A
,但是所引用的对象B
(在本例中恰好是一个类)与所引用的类之间绝对没有任何关系A
。
You can't call new on a module.
-从基本的角度来说,如果我只想为某些类命名,而无需实际创建外部“类” 的实例,则我会使用一个外部模块。但是,如果我要实例化包装/外部“类”的实例,则可以将其设为类而不是模块。至少这对我来说很有意义。
您可能想使用它将您的类分组为一个模块。某种名称空间的东西。
例如,Twitter gem使用命名空间来实现此目的:
Twitter::Client.new
Twitter::Search.new
因此,Client
和Search
类都生活在该Twitter
模块下。
希望这可以帮助!
在2.5之前的Ruby中,嵌套类和嵌套模块之间还有另一个区别,其他答案未能解决,我认为必须在这里提及。这是查找过程。
简而言之:由于Ruby在2.5之前的顶级常量查询,Object
如果您使用嵌套类,Ruby可能最终会在错误的位置(特别是)寻找嵌套类。
在2.5之前的Ruby中:
嵌套类结构:
假设您有一个X
带有嵌套类Y
或的类X::Y
。然后,您还具有一个名为的顶级类Y
。如果X::Y
没有加载,那么下面,当你调用情况X::Y
:
已经没有发现Y
的X
,红宝石会尝试看看它的祖先X
。以来X
是类而不是模块,它有祖先,其中有[Object, Kernel, BasicObject]
。因此,它将尝试Y
在Object
中找到成功的位置。
然而,这是最高级别Y
,而不是X::Y
。您将收到以下警告:
warning: toplevel constant Y referenced by X::Y
嵌套的模块结构:
在前面的示例中,假设X
是模块而不是类。
一个模块只有其自身是祖先:X.ancestors
将产生[X]
。
在这种情况下,Ruby将无法Y
在的祖先之一中寻找X
并将抛出NameError
。之后,Rails(或具有自动加载功能的任何其他框架)将尝试加载X::Y
。
请参阅本文以获取更多信息:https : //blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
在Ruby 2.5:
删除了顶级常量查询。
您可以使用嵌套类,而不必担心遇到此错误。
除了以前的答案:Ruby中的模块是一个类
$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object
new
。因此,尽管您可以说模块是一个类(小写),但它们与类(大写)是不同的:)
Car.new
和之间建立关系是什么意思Car::Wheel.new
。您绝对不需要初始化Car
对象即可Car::Wheel
在Ruby中初始化对象,但是Car
必须加载并执行该类才能Car::Wheel
使用。