En Rubí ¿hay aplicaciones relacionadas de la sintaxis: clase << auto ... fin
Pregunta
class << self
attr_accessor :n, :totalX, :totalY
end
La sintaxis anterior se utiliza para la definición de las variables de instancia de clase. Pero cuando pienso en lo que implica la sintaxis, no tiene ningún sentido para mí, así que me pregunto si este tipo de sintaxis se utiliza para cualquier otro tipo de definiciones. Mi punto de confusión aquí es la siguiente:
class << self
El operador de agregación normalmente significa "añadir lo que está a la derecha al objeto de la izquierda". Pero en el contexto de este bloque, ¿cómo que se suman a "poner el contenido de este bloque en la definición de la instancia de clase en lugar de la instancia"?
Por la misma razón por la que estoy confundido en cuanto a por qué en una clase de contexto << auto puede definir variables de instancia de clase, mientras que en otro se parece crear variables de clase, como aquí:
class Point
# Instance methods go here
class << self
# Class methods go here
end
end
Solución
en Ruby puede volver a abrir clases existentes y añadir métodos. Es decir, se puede decir:
class Foo
def bob
return "hello from bob"
end
end
estos métodos se almacenan en algún lugar de un diccionario interno (tal vez una variable de instancia) de la clase Foo
(que es sólo una instancia de la clase Class
y por lo tanto tiene variables de instancia)
Pero lo más sorprende es que también se puede añadir métodos a casos de los objetos existentes
foo = Foo.new
foo2 = Foo.new
def foo.fred
return "I am fred"
end
foo.fred #=> "I am fred"
foo2.fred #=> NoMethodError
y ¿Dónde está este método realmente se almacena
Resulta que Rubí crea una nueva clase detrás de las escenas (a veces llamado clase Singleton , metaclase o eigenclass ), que se inserta en la herencia jerarquía entre de la clase Foo
y su ejemplo.
Así que la relación de herencia se parece a lo siguiente:
foo < (eigenclass of foo) < Foo < Class
(si usted dice foo.superclass no verá la clase Singleton)
class << X
la sintaxis es una manera de llegar a esta clase especial, por lo que se puede manipular directamente. Los siguientes bloques de código son exactamente equivalentes:
def foo.bar
return "xy"
end
# is exactly the same as
class << foo
def bar
return "xy"
end
end
Así que la similitud entre class Foo < Bar
y class << Foo
no es accidental, no hay herencia pasando en ambos.
Piense en class << X
como "abrir el metaclase de X"
Lo que hay que recordar en Ruby es que las clases en sí son sólo objetos. (Las instancias de la clase Class
) por lo que si dicen:
class Foo
class << self
def k
return "x"
end
end
end
(self
está obligado a Foo
en este bloque de código), de modo k
es un método de instancia de los eigenclass de Foo
, que hace que sea un método de clase para Foo
todo esto se explica con mayor claridad en el capítulo del acerca de las clases de la piqueta (la versión web no contiene los diagramas, por desgracia) y _whys al ver metaclases Claramente
Otros consejos
Piense en la clase que contiene un diccionario de miembros, incluyendo todos los descriptores de acceso y las variables de instancia. Cuando le dices a la clase de "añadir" a "sí", que dice "agregar estos al diccionario de miembros de la clase."
Te concedo la notación es un poco hinky, sin embargo.
en realidad es confuso para pensar en ella en términos de un operador "añadir". una mejor forma de verlo es que así como class Foo
abre clase Foo, es decir, se establece 'sí' al objeto de clase Foo, creando si es necesario, por lo class << self
abre las eigenclass del objeto actual 'auto'. en cuenta que no se limita a la auto -. para cualquier barra de objetos, se puede decir que la clase << barra para abrir el eigenclass de ese objeto
class A
def hello
print "hello world"
end
end
a = A.new
b = A.new
class << a
def goodbye
print "goodbye cruel world"
end
end
a.hello
b.hello
a.goodbye
b.goodbye