¿Cuál es la diferencia entre class_eval y clase << classname?
-
28-10-2019 - |
Pregunta
Soy un iniciador de rubí. Encontré que ambos son bastante similares (en la salida), pero no pude entender la diferencia en el siguiente contexto. Por ejemplo, tengo una clase
class Say
def self.hello
puts "hello"
end
end
y se puede extender así
class << Say
def hi
puts "hi"
end
end
Y también como esto
Say.class_eval do
def self.bye
puts "bye"
end
end
Cuando debo usar <<
y cuando class_eval
?
Solución
class_eval
realmente no tiene nada que ver con class << className
.
A.class_eval do
...
end
es equivalente a
class A
...
end
con algunas diferencias. class_eval usa un bloque (o una cadena, pero ignorando eso por el momento), lo que significa que se cierra sobre el alcance léxico que contiene. En otras palabras, puede usar variables locales del alcance circundante. El bloque de clase común presenta un ámbito nuevo. Del mismo modo, puede crear el bloque y pasarlo a muchas class_eval diferentes, y el cuerpo del bloque se ejecutará en el contexto de la clase en la que está llamando class_eval.
class << className
abre la clase singleton de className
, permitiéndole definir métodos de clase.
class << A
def foo
...
end
end
Es lo mismo que
def A.foo
...
end
Tenga en cuenta que son métodos de clase Oly si es una clase (casi) todos los objetos en Ruby tienen clases de singleton y puede definir métodos para ellos utilizando cualquiera de esas dos sintaxis. La ventaja de class << obj
es principalmente si estás definiendo muchos métodos singleton de una vez.
Otros consejos
Como ya se dijo, class_eval realmente no tiene mucho que ver con
class <<self
Incluso si parecen hacer lo mismo en su ejemplo (si bien el efecto es similar, no hace lo mismo, hay diferencias sutiles).
Aquí hay otro ejemplo en el que el uso de la segunda forma es mucho más clara:
class A
end
a = A.new
b = A.new
class <<b
def say_hi
puts "Hi !"
end
end
b.say_hi # will print "Hi !"
a.say_hi # will raise an undefined method
A y B son ambos objetos de la misma clase A, pero agregamos un método a la metaclase de B, por lo que el método Say_hi solo está disponible para el objeto B.