我对何时使用子类和模块非常熟悉,但最近我一直在看这样的嵌套类:
class Foo
class Bar
# do some useful things
end
end
Run Code Online (Sandbox Code Playgroud)
以及嵌套在模块中的类如下:
module Baz
class Quux
# more code
end
end
Run Code Online (Sandbox Code Playgroud)
文档和文章都很稀疏,或者我没有足够的知识来搜索正确的搜索术语,但我似乎无法找到有关该主题的更多信息.
有人可以提供关于为何/何时使用这些技术的帖子的示例或链接?
Pan*_*kos 132
其他OOP语言具有内部类,如果不绑定到上级类,则无法实例化它们.例如,在Java中,
class Car {
class Wheel { }
}
Run Code Online (Sandbox Code Playgroud)
只有Car类中的方法才能创建Wheels.
Ruby没有那种行为.
在Ruby中,
class Car
class Wheel
end
end
Run Code Online (Sandbox Code Playgroud)
不同于
class Car
end
class Wheel
end
Run Code Online (Sandbox Code Playgroud)
只有在类的名称Wheel对Car::Wheel.这种名称差异可以使程序员明确表示Car::Wheel该类只能代表车轮,而不是一般的车轮.在Ruby中嵌套类定义是一个偏好的问题,但它有一个目的,即它更强有力地强制执行两个类之间的契约,并且这样做会传达有关它们及其用途的更多信息.
但是对于Ruby解释器来说,它只是名称上的差异.
至于你的第二个观察,嵌套在模块内的类通常用于命名类.例如:
module ActiveRecord
class Base
end
end
Run Code Online (Sandbox Code Playgroud)
不同于
module ActionMailer
class Base
end
end
Run Code Online (Sandbox Code Playgroud)
虽然这不是嵌套在模块内部的类的唯一用法,但它通常是最常见的.
Dig*_*oss 48
在Ruby中,定义嵌套类与在模块中定义类类似.它实际上并不强制类之间的关联,它只是为常量创建一个命名空间.(类和模块名称是常量.)
接受的答案对任何事情都不正确.1在下面的示例中,我创建了一个词法封闭类的实例,而没有一个封闭类的实例.
class A; class B; end; end
A::B.new
Run Code Online (Sandbox Code Playgroud)
优点与模块的优点相同:封装,仅在一个地方使用的分组代码,以及将代码放置在更接近使用位置的位置.一个大型项目可能有一个外部模块在每个源文件中反复出现,并包含许多类定义.当各种框架和库代码都执行此操作时,它们每个只为顶级提供一个名称,从而减少冲突的可能性.平淡无奇,可以肯定,但这就是他们被使用的原因.
使用类而不是模块来定义外部命名空间可能在单文件程序或脚本中有意义,或者如果您已经使用顶级类,或者如果您实际上要添加代码以将类链接在一起真正的内在风格.Ruby没有内部类,但没有什么能阻止你在代码中创建相同的行为.从内部对象引用外部对象仍然需要从外部对象的实例中加入点,但是嵌套类将表明这是您可能正在做的事情.精心模块化的程序可能总是首先创建封闭类,并且可以合理地使用嵌套类或内部类进行分解.你不能打电话new给模块.
即使对于脚本而言,您也可以使用通用模式,其中名称空间不是非常需要的,只是为了娱乐和练习......
#!/usr/bin/env ruby
class A
class Realwork_A
...
end
class Realwork_B
...
end
def run
...
end
self
end.new.run
Run Code Online (Sandbox Code Playgroud)
Pab*_*dez 15
您可能希望使用它将类分组到模块中.命名空间的东西.
例如,Twitter gem使用命名空间来实现这一点:
Twitter::Client.new
Twitter::Search.new
Run Code Online (Sandbox Code Playgroud)
所以这两个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
Run Code Online (Sandbox Code Playgroud)
嵌套的模块结构:
在上一个示例中,假设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:
删除了顶级常量查询。
您可以使用嵌套类,而不必担心遇到此错误。