有什么区别:
class A
class B
end
end
Run Code Online (Sandbox Code Playgroud)
和
class A
end
class A::B
end
Run Code Online (Sandbox Code Playgroud)
更新:这两种方法并不完全相同.
在第二种方法中,B无法访问定义的常量A.
另外,正如Matheus Moreira正确指出的那样,在第二种方法中,A必须先定义才能A::B定义.
还有什么其他差异?
在Ruby,模块和类是实例Module和Class分别类.它们从它们被赋予的常量中得出它们的名称.当你写:
class A::B
# ...
end
Run Code Online (Sandbox Code Playgroud)
你是在写作:
A::B ||= Class.new do
# ...
end
Run Code Online (Sandbox Code Playgroud)
这是有效的常数赋值语法,并假定该A常数已正确初始化并且,它指的是Module或Class.
例如,考虑如何定义类:
class A
# ...
end
Run Code Online (Sandbox Code Playgroud)
实际发生的是:
Object::A ||= Class.new do
# ...
end
Run Code Online (Sandbox Code Playgroud)
现在,当你写:
class A
class B
# ...
end
end
Run Code Online (Sandbox Code Playgroud)
实际发生的事情如下:
(Object::A ||= Class.new).class_eval do
(A::B ||= Class.new).class_eval do
# ...
end
end
Run Code Online (Sandbox Code Playgroud)
这是正在发生的事情,按顺序:
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
Run Code Online (Sandbox Code Playgroud)
根据这篇博客文章,Ruby核心团队称之为"当前类" cref.不幸的是,作者没有详细说明,但正如他所指出的那样,它与上下文不同self.
如此处所述,这cref是一个链表,表示模块在某个时间点的嵌套.
当前
cref用于恒定和类变量查找和def,undef和alias.
正如其他人所说,他们是表达同一事物的不同方式.
然而,有一个微妙的区别.在编写时class A::B,您假定A已经定义了该类.如果没有,你将得到一个NameError,B根本不会被定义.
编写正确嵌套的模块:
class A
class B
end
end
Run Code Online (Sandbox Code Playgroud)
A在尝试定义之前确保类存在B.