Qual è la differenza tra class_eval e class << className?
-
28-10-2019 - |
Domanda
Sono un antipasto di Ruby. Ho scoperto che entrambi sono abbastanza simili (in output), ma non riuscivo a capire la differenza nel contesto seguente. Ad esempio, ho una classe
class Say
def self.hello
puts "hello"
end
end
e può essere esteso in questo modo
class << Say
def hi
puts "hi"
end
end
E anche questo
Say.class_eval do
def self.bye
puts "bye"
end
end
Quando dovrei usare <<
e quando class_eval
?
Soluzione
class_eval
Non ha davvero nulla a che fare con class << className
.
A.class_eval do
...
end
è equivalente a
class A
...
end
con alcune differenze. Class_eval usa un blocco (o una stringa, ma ignorandolo per il momento) il che significa che si chiude sopra l'ambito lessicale contenente. In altre parole puoi usare le variabili locali dall'ambito circostante. Il Common Class Block introduce un ambito nuovo di zecca. Allo stesso modo puoi creare il blocco e passarlo a molte diverse classi di classe_eval e il corpo del blocco verrà eseguito nel contesto della classe su cui stai chiamando Class_Eval.
class << className
Apre la classe Singleton di className
, permettendoti di definire i metodi di classe.
class << A
def foo
...
end
end
Equivale a
def A.foo
...
end
Si noti che sono metodi di classe Oly se A è una classe (quasi) tutti gli oggetti in Ruby hanno classi singleton e puoi definire metodi per loro usando uno di questi due sintassi. Il vantaggio di class << obj
è principalmente se stai definendo molti metodi singleton in una volta.
Altri suggerimenti
Come già detto Class_eval non ha davvero molto a che fare con
class <<self
Anche se sembrano fare la stessa cosa nel tuo esempio (mentre l'effetto è simile, non fa lo stesso, ci sono sottili differenze).
Ecco un altro esempio in cui l'uso della seconda forma è molto più chiaro:
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 e B sono entrambi oggetti della stessa classe A, ma abbiamo aggiunto un metodo alla metaclasse di B, quindi il metodo Say_hi è disponibile solo per l'oggetto B.