2012-03-16 22 views
6

¿Cuál es la diferencia entre:Diferencia entre "clase A, la clase B" y "clase A :: B"

class A 
    class B 
    end 
end 

y

class A 
end 

class A::B 
end 

Actualización: Estos 2 enfoques no son exactamente lo mismo.

En el segundo enfoque, B no tiene acceso a las constantes definidas en A.

Además, como Matheus Moreira declaró correctamente, en el segundo enfoque, se debe definir A antes de que se pueda definir A::B.

¿Qué otras diferencias existen?

Respuesta

8

En Ruby, módulos y clases son instancias de las clases Module y Class, respectivamente. Derivan sus nombres de la constante a la que están asignados. Cuando se escribe:

class A::B 
    # ... 
end 

Estás escribiendo con eficacia:

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

Cuál es la sintaxis de asignación constante válida, y asume que la constante A ha sido inicializado correctamente y que se refiere a una Module o Class.

Por ejemplo, considere cómo las clases se definen generalmente:

class A 
    # ... 
end 

Lo que está pasando con eficacia es la siguiente:

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

Ahora, cuando escribe:

class A 
    class B 
    # ... 
    end 
end 

Lo que en realidad El resultado se ve así:

(Object::A ||= Class.new).class_eval do 
    (A::B ||= Class.new).class_eval do 
    # ... 
    end 
end 

Esto es lo que está pasando, en orden:

  1. Una nueva instancia se Class asssigned a la A constante de Object, a menos que ya se ha inicializado.
  2. Se asigna una nueva instancia de Class a la constante B de A, a menos que ya se haya inicializado.

Esto asegura la existencia de todos clases exteriores antes de intentar definir cualquier clases internas.

También hay un cambio en el alcance, que le permite acceder directamente a las constantes de A. Compare:

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 

Según this blog post, el equipo central de Rubí llama a la "clase actual" la cref. Desafortunadamente, el autor no detalla, pero como señala, está separado del contexto de self.


As explained here, el cref es una lista vinculado que representa el anidamiento de módulos en un cierto punto en el tiempo.

La corriente cref se utiliza para constante y clase de búsqueda variable y para def, undef y alias.


Como los otros han dicho, son diferentes maneras de expresar la misma cosa.

Hay, sin embargo, una diferencia sutil. Cuando escribe class A::B, asume que la clase A ya se ha definido. Si no lo ha hecho, obtendrá un NameError y B no se definirá en absoluto.

escritura módulos correctamente anidados:

class A 
    class B 
    end 
end 

Asegura la clase A existe antes de intentar definir B.

+1

He actualizado la pregunta para mostrar que estos 2 enfoques no son lo mismo. – nickh

+0

@nickh, no necesita editar la pregunta para incluir las respuestas. Debería [respaldar las respuestas que fueron útiles y aceptar la que definitivamente respondió su pregunta] (http://stackoverflow.com/faq#howtoask). –

+0

El caso es que ninguno de ellos respondió la pregunta. Todas las respuestas dicen que los 2 enfoques son los mismos, que no lo son. – nickh

1

Son lo mismo. Son formas diferentes de escribir lo mismo. El primero es la manera ingenua de escribirlo, pero a menudo, es difícil hacer un seguimiento de la anidación una vez que la clase/módulo crece. Usando la segunda manera, puede evitar anidar en la apariencia.

+1

He actualizado la pregunta para mostrar que estos 2 enfoques no son los mismos. – nickh

+0

@nickh Pensé que esas diferencias son triviales y presupuestas, así que no las mencioné. Señalarlos no es muy diferente de decir "bueno, la cadena 'clase B' parece diferente de 'clase A :: B'", pero no lo mencionaste. – sawa

3

Dos formas diferentes de decir lo mismo. Eso es que la clase B es una clase interna o anidada y solo se puede acceder a través de la interfaz 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" 

frente

> 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" 
> 
+1

He actualizado la pregunta para mostrar que estos 2 enfoques no son lo mismo. – nickh

Cuestiones relacionadas