Ruby方法调用层次结构

dyn*_*nex 5 ruby

本文的启发下,我正在使用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
Run Code Online (Sandbox Code Playgroud)

运行它给出:

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
Run Code Online (Sandbox Code Playgroud)

我的问题是:

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

我原本b.method_missing(method)应该先调用,然后是类的实例method_missing(method)(因为我调用super?但是super是类层次结构......),重定向bar到的是foo.另外,为什么在被重定向后foo调用实例的missing_method?我们刚被告知我们正被重定向......

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

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

Nik*_* B. 4

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

method_missing (bar) on b. Redeirecting to b.foo
method_missing (bar) on b. Calling super
Run Code Online (Sandbox Code Playgroud)

乍一看,这给人的印象是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