有什么区别:
class A
class B
end
end
和
class A
end
class A::B
end
更新:这两种方法并不完全相同。
在第二种方法中,B
无法访问 A
中定义的常量。
此外,正如 Matheus Moreira 正确指出的那样,在第二种方法中,必须在定义 A::B
之前定义 A
。
还有哪些区别?
最佳答案
在 Ruby 中,模块和类是 Module
的实例和 Class
类,分别。它们的名称来自分配给它们的常量。当你写:
class A::B
# ...
end
您正在有效地编写:
A::B ||= Class.new do
# ...
end
这是有效的常量赋值语法,并且假设 A
常量已正确初始化并且它指的是模块
或类
。
例如,考虑类通常是如何定义的:
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
实例被分配给Object
的A
常量,除非它已经被初始化。 - 一个新的
Class
实例被分配给A
的B
常量,除非它已经被初始化。
这确保在尝试定义任何 内部类之前存在所有 外部类。
作用域也发生了变化,它允许您直接访问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
是一个链表,表示模块在某个时间点的嵌套。
The current
cref
is used for constant and class variable lookup and fordef
,undef
andalias
.
正如其他人所说,它们是表达同一事物的不同方式。
但是,有一个细微的差别。当您编写 class A::B
时,您假定 A
类已经定义。如果没有,您将得到一个 NameError
并且 B
根本不会被定义。
编写正确嵌套的模块:
class A
class B
end
end
在尝试定义 B
之前确保 A
类存在。
关于ruby - "class A; class B"和 "class A::B"之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9739588/