"A类; B类"与"A类:: B类"之间的区别

nic*_*ckh 6 ruby

有什么区别:

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定义.

还有什么其他差异?

Mat*_*ira 8

在Ruby,模块和类是实例ModuleClass分别类.它们从它们被赋予的常量中得出它们的名称.当你写:

class A::B
  # ...
end
Run Code Online (Sandbox Code Playgroud)

你是在写作:

A::B ||= Class.new do
  # ...
end
Run Code Online (Sandbox Code Playgroud)

这是有效的常数赋值语法,并假定A常数已正确初始化并且,它指的是ModuleClass.

例如,考虑如何定义类:

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)

这是正在发生的事情,按顺序:

  1. 除非已初始化,否则新Class实例将被赋值为A常量Object.
  2. 除非已初始化,否则新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,undefalias.


正如其他人所说,他们是表达同一事物的不同方式.

然而,有一个微妙的区别.在编写时class A::B,您假定A已经定义了该类.如果没有,你将得到一个NameError,B根本不会被定义.

编写正确嵌套的模块:

class A
  class B
  end
end
Run Code Online (Sandbox Code Playgroud)

A在尝试定义之前确保类存在B.

  • 如何定义常量的很好的解释.谢谢!知道为什么`B`在使用`class A :: B`定义`B`时无法访问`A`中的常量? (2认同)