ruby - "class A; class B"和 "class A::B"之间的区别

标签 ruby

有什么区别:

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

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

  1. 一个新的 Class 实例被分配给 ObjectA 常量,除非它已经被初始化。
  2. 一个新的 Class 实例被分配给 AB 常量,除非它已经被初始化。

这确保在尝试定义任何 内部类之前存在所有 外部类。

作用域也发生了变化,它允许您直接访问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 herecref 是一个链表,表示模块在某个时间点的嵌套。

The current cref is used for constant and class variable lookup and for def, undef and alias.


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

但是,有一个细微的差别。当您编写 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/

相关文章:

ruby - 可枚举模块如何通过在 Ruby 中的类上添加 each 方法来工作?

ruby - 下一个元素是 (current+1) 或 0 (ruby)

ruby-on-rails - 在 Ruby Gem 中包含自定义辅助方法

ruby-on-rails - 经典哈希到点符号哈希

ruby - Splat 参数与 Espresso

ruby-on-rails - DatabaseCleaner 引发 NoMethodError : undefined method `rollback' for nil:NilClass

ruby-on-rails - 配置非静态路由

ruby-on-rails - Rails 数组 group_by

ruby-on-rails - 使用正则表达式根据用户名的最后一个字母更改文本

c - 如何将语言绑定(bind)到 C 库