[英]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.