“A类; B类”与“A类:: B类”之间的区别

时间:2012-03-16 14:57:00

标签: ruby

有什么区别:

class A
  class B
  end
end

class A
end

class A::B
end

更新:这两种方法并不完全相同。

在第二种方法中,B无法访问A中定义的常量。

另外,正如Matheus Moreira所说,在第二种方法中,A必须在定义A::B之前定义。

还有其他什么差异?

3 个答案:

答案 0 :(得分:8)

在Ruby中,模块和类分别是ModuleClass类的实例。它们的名称来自它们所分配的常量。当你写:

class A::B
  # ...
end

你实际上在写:

A::B ||= Class.new do
  # ...
end

哪个是有效的常量赋值语法,假定 A常量已正确初始化它指的是ModuleClass

例如,考虑如何定义类:

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个实例被分配到A Object常量,除非它已经初始化。
  2. 新的Class个实例被分配到B A常量,除非它已经初始化。
  3. 在尝试定义任何内部类之前,这确保了所有外部类的存在。

    范围也有变化,允许您直接访问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链接列表,表示某些时间点的模块嵌套。

      

    当前cref用于常量和类变量查找和   适用于defundefalias


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

    然而,有一个微妙的区别。当您编写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.s­ay
=> "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.s­ay
=> "In B"
>  

答案 2 :(得分:1)

他们是一样的。它们是写同一件事的不同方式。第一个是编写它的天真方式,但通常,一旦类/模块变大,就很难跟踪嵌套。使用第二种方法,可以避免在外观中嵌套。