繁体   English   中英

使用`instance_eval`

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM