有什么区别:
class A
class B
end
end
和
class A
end
class A::B
end
更新:这两种方法并不完全相同。
在第二种方法中,B
无法访问A
中定义的常量。
另外,正如Matheus Moreira所说,在第二种方法中,A
必须在定义A::B
之前定义。
还有其他什么差异?
答案 0 :(得分:8)
在Ruby中,模块和类分别是Module
和Class
类的实例。它们的名称来自它们所分配的常量。当你写:
class A::B
# ...
end
你实际上在写:
A::B ||= Class.new do
# ...
end
哪个是有效的常量赋值语法,假定 A
常量已正确初始化和它指的是Module
或Class
。
例如,考虑如何定义类:
class A
# ...
end
实际发生的是:
Object::A ||= Class.new do
# ...
end
现在,当你写:
class A
class B
# ...
end
end
实际发生的事情如下:
(Object::A ||= Class.new).class_eval do
(A::B ||= Class.new).class_eval do
# ...
end
end
以下是正在发生的事情:
Class
个实例被分配到A
Object
常量,除非它已经初始化。Class
个实例被分配到B
A
常量,除非它已经初始化。在尝试定义任何内部类之前,这确保了所有外部类的存在。
范围也有变化,允许您直接访问A
的常量。比较:
class A
MESSAGE = "I'm here!"
end
# Scope of Object
class A::B
# Scope of B
puts MESSAGE # NameError: uninitialized constant A::B::MESSAGE
end
# Scope of Object
class A
# Scope of A
class B
# Scope of B
puts MESSAGE # I'm here!
end
end
根据this blog post,Ruby核心团队将“当前类”称为cref
。不幸的是,作者没有详细说明,但正如他所指出的,它与self
的背景是分开的。
As explained here,cref
是链接列表,表示某些时间点的模块嵌套。
当前
cref
用于常量和类变量查找和 适用于def
,undef
和alias
。
正如其他人所说,他们是表达同一事物的不同方式。
然而,有一个微妙的区别。当您编写class A::B
时,假设已经定义了A
类。如果没有,您将获得NameError
并且根本不会定义B
。
正确编写嵌套模块:
class A
class B
end
end
在尝试定义A
之前确保B
类存在。
答案 1 :(得分:3)
两种不同的方式来说同样的事情。那就是B类是内部类或嵌套类,只能通过A接口访问。
> class A
.. def say
.... "In A"
....end
..
.. class B
.... def say
...... "In B"
......end
....end
..end
=> nil
> A.new.say
=> "In A"
> B.new.say
=> #<NameError: uninitialized constant B>
> A::B.new.say
=> "In B"
与
> class A
.. def say
.... "In A"
....end
..end
=> nil
> class A::B
.. def say
.... "In B"
....end
..end
=> nil
> A.new.say
=> "In A"
> B.new.say
=> #<NameError: uninitialized constant B>
> A::B.new.say
=> "In B"
>
答案 2 :(得分:1)
他们是一样的。它们是写同一件事的不同方式。第一个是编写它的天真方式,但通常,一旦类/模块变大,就很难跟踪嵌套。使用第二种方法,可以避免在外观中嵌套。