在方法重新定义中访问超类方法的问题

时间:2010-12-13 07:06:26

标签: ruby methods extending

我很难理解什么时候可以调用“超级”,什么时候不能。在下面的示例中,super方法导致无超类错误。

class Bacterium
  def eats
    puts "Nam"
  end
end

class Bacterium
  def eats
    super # -> no superclass error
    puts "Yam"
  end
end

b = Bacterium.new
b.eats

但这有效:

class Fixnum
  def times
    super # -> works
    puts "done"
  end
end

5.times { |i| puts i.to_s }

5不仅仅是Fixnum的一个实例。我是不是在重新定义现有方法,如上面的细菌例子?

2 个答案:

答案 0 :(得分:3)

不,不是真的。 Fixnum继承自Integer类,您实际上覆盖了Integer#times,因此super可以正常工作,因为它从父级调用实现。

为了在monkeypatching时实现类似的功能,你应该在重新定义之前使用别名方法,并通过别名调用它。

class Bacterium
  alias_method :eats_original, :eats
  def eats
    eats_original # -> "Nam"
    puts "Yam"
  end
end

类重新开放不是一种继承形式,super在那里没用。

答案 1 :(得分:3)

正如Mladen所说,您可以使用Class#superclass检查:

irb> Fixnum.superclass
=> Integer

整数是否实现了#times?:

irb> Integer.instance_methods.grep /times/
=> [:times]

是的。

因此,以简化的方式,我们可以说,super调用您在超类中的方法。在您的情况下,Bacterium的超类是Object,它不实现#eats

我说这很简单,因为看看这个例子:

module One
  def hi
    " World" << super()
  end
end

module Two
  def hi
    "Hello" << super()
  end
end

class SayHi
  def hi
    "!!!"
  end
end

h = SayHi.new
h.extend(One)
h.extend(Two)

puts h.hi

#=> Hello World!!

不要认真对待我在这里所写的内容,它实际上是Ruby对象模型的冰山一角,这对于理解很重要(我还在学习它) - 那么你将获得大部分或全部概念

使用一些Google-fu作为“Ruby对象模型”......