簡體   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