2009-10-27 13 views
74

Me he perdido la nota en alguna parte, y espero que me lo expliques.¿Por qué la clase de usuario no es equivalente a self.class, cuando parece tan similar?

¿Por qué el eigenclass de un objeto diferente de self.class?

class Foo 
    def initialize(symbol) 
    eigenclass = class << self 
     self 
    end 
    eigenclass.class_eval do 
     attr_accessor symbol 
    end 
    end 
end 

Mi tren de la lógica que equipara los eigenclass con class.self es bastante simple:

class << self es una forma de declarar métodos de clase, en lugar de los métodos de instancia. Es un atajo al def Foo.bar.

Por lo tanto, dentro de la referencia al objeto de clase, devolver self debe ser idéntico a self.class. Esto se debe a que class << self establecería self en Foo.class para la definición de los métodos/atributos de clase.

¿Estoy confundido? O, ¿es este un truco furtivo de la meta-programación de Ruby?

Respuesta

106

class << self es más que una forma de declarar métodos de clase (aunque puede ser utilizado de esa manera). Probablemente usted ha visto un cierto uso como:

class Foo 
    class << self 
    def a 
     print "I could also have been defined as def Foo.a." 
    end 
    end 
end 

Esto funciona, y es equivalente a def Foo.a, pero la forma en que funciona es un poco más sutil. El secreto es que self, en ese contexto, se refiere al objeto Foo, cuya clase es una subclase anónima única de Class. Esta subclase se llama Foo 's eigenclass. Así def a crea un nuevo método llamado a en eigenclass Foo 's, con acceso por la sintaxis normal de llamada al método: Foo.a.

Ahora vamos a ver un ejemplo diferente:

str = "abc" 
other_str = "def" 

class << str 
    def frob 
    return self + "d" 
    end 
end 

print str.frob # => "abcd" 
print other_str.frob # => raises an exception, 'frob' is not defined on other_str 

Este ejemplo es el mismo que el anterior, aunque puede ser difícil saber en un principio. frob se define, no en la clase String, sino en las eigenclass de str, una subclase anónima única de String. Entonces str tiene un método frob, pero las instancias de String en general no. También podríamos haber reemplazado los métodos de String (muy útil en ciertos escenarios difíciles de prueba).

Ahora estamos preparados para entender su original ejemplo. Dentro del método de inicialización Foo, self no se refiere a la clase Foo, sino a alguna instancia particular de Foo. Su clase propia es una subclase de Foo, pero no es Foo; no podría ser, o el truco que vimos en el segundo ejemplo no podría funcionar. Para continuar su ejemplo:

f1 = Foo.new(:weasels) 
f2 = Foo.new(:monkeys) 

f1.weasels = 4 # Fine 
f2.monkeys = 5 # Also ok 
print(f1.monkeys) # Doesn't work, f1 doesn't have a 'monkeys' method. 

Espero que esto ayude.

+0

Así pues, cada instancia es una subclase de la clase anónima creada? –

+19

clase de * * Cada instancia es una subclase anónima de la clase creada. La clase de f1 es una subclase anónima de Foo, la clase de Foo es una subclase anónima de Clase. –

+4

nice answer :) mucha gente no entiende esto tan claramente como tú. – horseyguy

43

La respuesta más simple: los eigenclass no se pueden crear instancias.

class F 
def eigen 
    class << self 
    self 
    end 
end 
end 
F.new.eigen.new #=> TypeError: can't create instance of virtual class 
+0

es posible que tenga solo 1 punto en este sitio web, pero me gustas a ti y a tu estilo. – horseyguy

+0

De acuerdo con barandilla; esto es una gran respuesta –

+1

información interesante, pero no responde a la pregunta – Alexey

Cuestiones relacionadas