【问题标题】:Ruby metaprogramming: instance_eval and class_evalRuby 元编程:instance_eval 和 class_eval
【发布时间】:2015-02-08 06:43:03
【问题描述】:

虽然我已经使用了一段时间,但似乎我对这两种方法感到困惑,我不明白为什么方法 passengers 没有被添加到以下代码中的对象中:

class Bus
  def number_of_seats
    42
  end
end

Bus.class_eval do
  define_method :number_of_windows do
    number_of_seats
  end

  def fuel_type
    :diesel
  end
end

Bus.instance_eval do
  define_method :destination do
    'Paris'
  end

  def passengers
    12
  end
end

bus = Bus.new
bus.number_of_windows # => 42
bus.fuel_type # => :diesel
bus.destination # => "Paris"
bus.passengers # => undefined method `passengers' (NoMethodError)

注意事项

  • 先尝试instance_eval,随机使用class_eval,然后好像也奏效了!
  • 我对@9​​87654324@的块的理解:块中的代码运行时将self设置为调用instance_eval的对象。
  • 我对@9​​87654327@ 块的理解:块中的代码是通过打开调用它的对象的类来评估的。因此,在上述情况下,我对class_eval 感到困惑!我期待 Bus 上的 class_eval 意味着评估 Bus Classclass 中的块。

【问题讨论】:

  • 方法passengers 工作正常:Bus.passengers #=> 12。将Bus.instance_eval 更改为Bus.class_eval 以使passengers 成为实例方法。
  • 你也可以使用Bus.send(:define_method, :passengers) { 12 }
  • 除了“事情如何运作”之外,这绝对是非常奇怪的行为。

标签: ruby metaprogramming


【解决方案1】:

你可以参考this关于类的精彩文章和instance_eval,了解为什么乘客没有被添加到对象中。

TL;DR:

Bus.class_eval will 创建实例方法,Bus.instance_eval 将创建类方法。

现在,关于 destination(可以在实例上调用)的行为.....class_evalinstance_eval 中使用时定义方法不受通常的行为。为什么?

因为文档是这样说的。根据文档:

define method - 在接收器中定义一个实例方法。

因此,无论您在class_evalinstance_eval 中使用define_method,它总是会创建一个实例方法。

Source for reference.

希望这会有所帮助:-)。

【讨论】:

    【解决方案2】:

    在使用def 时,基本上你不能对类对象执行instance_eval。这是您使用instance_evalclass_eval 的一般方式。 http://web.stanford.edu/~ouster/cgi-bin/cs142-winter15/classEval.php

    【讨论】:

      猜你喜欢
      • 2017-04-22
      • 2011-05-23
      • 2012-05-05
      • 2011-03-26
      • 1970-01-01
      • 2011-03-11
      • 2011-03-02
      • 1970-01-01
      • 2011-04-01
      相关资源
      最近更新 更多