首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用`instance_eval`

使用`instance_eval`
EN

Stack Overflow用户
提问于 2015-10-15 18:04:19
回答 2查看 665关注 0票数 1

我正在阅读为什么的ruby的辛酸指南,在第6章中,他使用了以下代码:

代码语言:javascript
复制
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_evalmetaclass添加了方法,所以他可以这样做:

代码语言:javascript
复制
def self.metaclass; self; end;

还是我错了?有没有更好的解决方案呢?

EN

回答 2

Stack Overflow用户

发布于 2015-10-15 23:18:44

编写_为什么的代码的更简单的方法是

代码语言:javascript
复制
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

这里唯一的问题是你会得到一个错误:

代码语言:javascript
复制
private method `define_method' called for metaclass (NoMethodError)

私有方法只能通过隐式接收器调用,即问题出在方法调用之前的显式metaclass.。但是如果我们去掉它,隐式接收器(self)就是Creature!那么如何将self更改为不同的对象呢?instance_eval

代码语言:javascript
复制
metaclass.instance_eval do
  define_method(a) do |val|
    ...
  end
end

因此,这实际上是一种绕过define_method是私有的事实的方式。另一种破解它的方法是使用send

代码语言:javascript
复制
metaclass.send(:define_method, a) do |val|
  ...
end

但现在,所有这些都是完全没有必要的;你可以在元类(AKA singleton类)中定义方法,而不需要绕过私有方法:

代码语言:javascript
复制
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
票数 2
EN

Stack Overflow用户

发布于 2015-10-15 18:27:40

如果你这样做了

代码语言:javascript
复制
def self.metaclass; self; end;

您将拥有对Creature类的引用。因此,在这种情况下,方法将不会被定义到对象Creature的单个类,而是被定义到类Creature本身(定义到类Creature的实例方法列表中)。该方法

代码语言:javascript
复制
def self.metaclass; class << self; self; end; end

是在ruby < 1.9中检索Creature对象的单个类的简单方法。在ruby 1.9+中实现了class << self的快捷方法singleton_class。因此代码可以简化为:

代码语言:javascript
复制
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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33145581

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档