Ruby方法调用层次结构

时间:2012-01-01 19:31:42

标签: ruby

受到这个article的启发,我正在玩Ruby方法调用层次结构并注意到一些奇怪的东西。

假设:

class B
  def foo  
    "- Instance method defined by B"
  end  

  def method_missing(method)
    puts "- method_missing (#{method}) on b. Redirecting to b.foo\n"
    foo
  end
end

b = B.new

def b.foo  
  "- Method defined directly on an instance of B\n" + super  
end

def b.method_missing(method)
  "- method_missing (#{method}) on b. Calling super\n" + super
end

puts "Calling 'bar' on b of type #{b.class}:"
puts b.bar

运行它给出:

Calling 'bar' on b of type B:
- method_missing (bar) on b. Redeirecting to b.foo
- method_missing (bar) on b. Calling super
- Method defined directly on an instance of B
- instance method defined by B

我的问题是:

由于我在调用b.bar(在对象上),为什么在调用objet的实例方法之前调用类的实例方法?

我本来期望首先调用b.method_missing(method),然后调用类的实例method_missing(method)(因为我调用super?但是super是类层次结构...),它从{{重定向1}}到bar。 另外,在被重定向到foo之后,如何调用实例的missing_method?我们刚被告知我们正被重定向......

我认为我不理解Ruby如何允许在类的实例上定义实例方法(对我来说是新的),而不是将其定义为类的实例方法(经典语言)

我希望这个问题有道理,也许我的头脑仍在从昨晚开始......

1 个答案:

答案 0 :(得分:4)

问题是您的输出不反映实际的执行顺序。我们来看看输出:

method_missing (bar) on b. Redeirecting to b.foo
method_missing (bar) on b. Calling super

乍一看,这给人的印象是在单例方法B#method_missing之前调用b.method_missing,这会引发您描述的两个问题。实际上,b.method_missing首先被正确调用。如果您查看语句puts b.bar的评估方式,这一点就很明确了:

  1. b没有方法bar,因此使用字符串b.method_missing作为参数调用'bar'
  2. b.method_missing依次使用B#method_missing关键字调用方法super
  3. B#method_missing使用puts输出上面的第一行
  4. 单身方法b.foo被称为
  5. 执行最外面的puts,输出b.method_missing中的字符串以及b.foo的返回值