ruby language-features eigenclass

ruby - ¿Por qué la clase de auto equivalente no es equivalente a self.class, cuando parece tan similar?



language-features eigenclass (3)

La respuesta más simple: la clase de genes no puede ser instanciada.

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

Me he perdido la nota en alguna parte, y espero que me lo expliques.

¿Por qué la clase de auto de un objeto es 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 lógica que iguala la clase propia con class.self es bastante simple:

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

Entonces, dentro de la referencia al objeto de la clase, el self regresa debe ser idéntico a self.class . Esto se debe a que class << self se establecería a 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?



class << self es más que una forma de declarar métodos de clase (aunque se puede usar de esa manera). Probablemente has visto un 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 sutil. El secreto es que self , en ese contexto, se refiere al objeto Foo , cuya clase es una subclase única y anónima de Class . Esta subclase se llama eigenclass de Foo . Así que def a crea un nuevo método llamado a en la clase propia de Foo , accesible mediante la sintaxis de llamada al método normal: Foo.a

Ahora veamos 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 de decir al principio. frob se define, no en la clase String , sino en la clase propia 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 equipados para comprender su ejemplo original. Dentro del método de inicialización de Foo , el 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. Entonces para continuar tu 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.