[英]Using `instance_eval`
我正在閱讀為什么是紅寶石的辛辣指南,在第6章中,他使用了以下代碼:
class Creature
# Get a metaclass for this class
def self.metaclass; class << self; self; end; end
...
def self.traits( *arr )
# 2. Add a new class method to for each trait.
arr.each do |a|
metaclass.instance_eval do
define_method( a ) do |val|
@traits ||= {}
@traits[a] = val
end
end
end
end
end
為什么他在Creature
類的元類上調用instance_eval
? 由於instance_eval
將方法添加到metaclass
,他可以這樣做:
def self.metaclass; self; end;
還是我錯了? 還有其他更優雅的解決方案嗎?
如果你這樣做
def self.metaclass; self; end;
您將參考Creature
類。 所以,在這種情況下,該方法將被定義為不將單例類對象的Creature
,但對類Creature
本身(到類的實例方法列表Creature
)。 方法
def self.metaclass; class << self; self; end; end
是在<1.9以下的ruby中檢索對象Creature
單例類的簡單方法。 在ruby 1.9+中實現了方法singleton_class
,這是class << self
快捷方式。 這樣該代碼可以簡化為:
class Creature
...
def self.traits( *arr )
# 2. Add a new class method to for each trait.
arr.each do |a|
singleton_class.instance_eval do
define_method( a ) do |val|
@traits ||= {}
@traits[a] = val
end
end
end
end
end
編寫_why代碼的更簡單方法是
def self.traits( *arr )
# 2. Add a new class method to for each trait.
arr.each do |a|
metaclass.define_method(a) do |val|
@traits ||= {}
@traits[a] = val
end
end
end
唯一的問題是出現錯誤:
private method `define_method' called for metaclass (NoMethodError)
只能使用隱式接收方調用私有方法,即問題是顯式metaclass.
在方法調用之前。 但是,如果我們刪除它,隱式接收者( self
)就是Creature
! 那么我們如何將self
變成另一個對象呢? instance_eval
:
metaclass.instance_eval do
define_method(a) do |val|
...
end
end
因此,這實際上只是繞過define_method
是私有的事實的一種方式。 破解的另一種方法是使用send
metaclass.send(:define_method, a) do |val|
...
end
但是如今,這一切都是完全不必要的。 您可以在元類(AKA單例類)中定義方法,而不必亂砍私有方法:
def self.traits( *arr )
# 2. Add a new class method to for each trait.
arr.each do |a|
define_singleton_method(a) do |val|
@traits ||= {}
@traits[a] = val
end
end
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.