Ruby 中的 super 关键字

yufei       6 年, 3 月 前       1757

本章节,我们来了解下 Ruby 中的 super 关键字,我们会讲述以下内容

  1. 隐式参数
  2. super VS super()
  3. super 和块
  4. super 和祖先链

隐式参数

当一个带参数的方法被其子类之一重写 ( override ) 时,那么可以在子类重写的方法中调用不带参数也不带括号的 super 会自动将子方法的参数传递给父方法。

我们用一个示例来演示下这个机制

class Parent
  def say(message)
    puts message
  end
end

class Child < Parent
  def say(message)
    super
  end
end
irb> Child.new.say('Hi!')
Hi!

上面的范例中,类 Child 继承自 Parent 类。然后还重写了 Parent 类中的 Parent#say 方法。

Child#say 方法内部,我们使用 super 关键字调用父类相应的方法 Parent#say ,并且会把 message 参数自动传递给 Parent#say 方法。

使用 super 关键字,Ruby 会自动在 Child 的祖先链 ancestors chain 中查找 #say 方法,找到了之后就会自动调用该方法并传递 message 作为参数。

如果你对 「 祖先链 」 不熟悉,那么可以访问我们的 Ruby 中的对象模型 ( object model ) ( 上 ) 来了解详情。

但是

我想,你也有同样的疑问 :如果祖先链中的 Parent#say 是一个不带参数的方法,那结果会怎么样 ?

这就涉及到 supersuper() 相关的知识了。

super VS super()

为了解决上面刚刚提到的问题,我们重新定义 Parent#say 方法,移除 message 参数,就像下面这样

class Parent
  def say
    puts "I'm the parent"
  end
end

class Child < Parent
  def say(message)
    super
  end
end
irb> Child.new.say('Hi!')
ArgumentError (wrong number of arguments (given 1, expected 0))

运行上面的代码会发现抛出了 ArgumentError (wrong number of arguments (given 1, expected 0)) 异常。

因为 Parent#say 方法是一个不带参数的方法,它不需要任何参数,但在 Child#say 方法中的 super 关键字却会将参数 message 隐式的传递给 Parent#say

为了避免这个问题,也为了解决这个问题,我们可以明确的指出 super 不需要把子类中相关的参数传递给父类。为此,我们需要在 super 后添加一对小括号 () ,即 super() 明确的调用父类而不传递任何参数

class Parent
  def say
    puts "I'm the parent"
  end
end
class Child < Parent
  def say(message)
    super()
  end
end
irb> Child.new.say('Hi!')
I'm the parent

这就是 supersuper() 的区别,super 会自动将子方法的参数传递给父方法,但 super() 则不会。

super 和块

因为 「 块 」 ( block ) 作为参数如此常见,那么我们要如何在子类中将一个块传递给父类呢 ?

不管三七二十一,我们先修改下代码再说,修改 Parent#say 方法接收一个块作为参数

class Parent
  def say
    yield
  end
end

class Child < Parent
  def say
    super
  end
end

irb> Child.new.say { puts 'Hi! Glad to know you Parent!' }
Hi! Glad to know you Parent!

哇塞,使用 super 关键字运行正常。

使用 super 关键字会自动将传递给子类方法 Child.new.say 的块传递给父类 Parent#say 方法。

Parent#say 方法中,我们使用 yield 关键字捕获一个块,并且执行它。

更多 yield 的知识,可以访问我们的 Ruby 中的 yeild 关键字 ( 上 )Ruby 中的 yeild 关键字 ( 下 )

super 和祖先链

为了测试更多祖先链的情况,我们修改下 Parent 类,让它继承自 GrandParent,并在 GrandParent 中也定义一个同样的 say 方法。

然后去掉 Parent 类中的 say 方法

class GrandParent
  def say(message)
    puts "GrandParent: #{message}"
  end
end

class Parent < GrandParent
end

class Child < Parent
  def say(message)
    super
  end
end

irb> Child.new.say('Hi!')
GrandParent: Hi!

上面的代码中,Child#say 方法的 super 首先会尝试在 Parent 类中找寻 say 方法,如果找到了就调用该方法,如果没找到,就会继续在祖先链上查找,直到找到为止 GrandParent#say

所以,运行结果就是调用 GrandParent#say 方法输出 GrandParent: Hi!

有关 Ruby 中的 super 关键字知识就这些。

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.