`

Ruby的函数调用与super

阅读更多

最近在巩固Ruby 的基本语法知识,在这里把以前一些不知道的特性一一总结下来。

在Ruby中是允许method的重复声明的,并且在合适的时候还允许你去一个一个调用(利用super关键字)。

在这里通过几个实例,我将和大家分享一下Ruby的method查找路径和方式以及super的使用和参数问题。

首先,让大家来看看这样一个例子:

class A
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

 输出结果是:

Output 写道
:!ruby method01.rb
"a 2"
method01.rb:7:in `a': super: no superclass method `a' (NoMethodError)
from method01.rb:13


shell returned 1

 从结果中,我们可以发现:如果在一个class里面重复声明两个同样的方法(同样的method名称和参数数目 ),原先的方法将被后面的方法完全覆盖掉(即原先的定义无效了) 。当然这是一个很正常的状况,在Java中语法直接不允许。这里虽然允许了,但是没有什么实际上面的意义。那么这里的super是什么意义呢?让我们慢慢来看。

让我们看看第二个例子:

class B
  def a 
    p 'B a 1'
  end
end

class A < B
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

输出结果:

Output 写道
:!ruby method01.rb
"a 2"
"B a 1"
"a 2 END"

 似乎很怪异吧,这就是Ruby中super关键字的一部分作用了。其实有点像Java中的Method overwrite 然后在通过super.XXXMethod去调用祖先方法,其中执行的顺序也是类似的。例子中,我们也看到了那个原先定义在A中的a方法确实没有用了。

类层次关系 写道
A<B
 

其实Module也有类似的效果:

module B
  def a 
    p 'B a 1'
  end
end

class A
  include B
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

 输出结果同上面的那个Class-Class的例子:

Output 写道
:!ruby method01.rb
"a 2"
"B a 1"
"a 2 END"
 
类层次关系 写道
A<M

 上面两个的层次关系其实也是method的查找顺序。好像Module和Class有同等效力,那么我们来将两个组合起来。

class B
  def a
    p 'B a 1'
  end
end

module M 
  def a 
    p 'M a 1'
    super
    p 'M a END'
  end
end

class A < B
  include M
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

 输出结果:

Output 写道
:!ruby method01.rb
"a 2"
"M a 1"
"B a 1"
"M a END"
"a 2 END"

 那么我们可以看到这个的层次结构了:

类层次结构 写道
A<M<B

 也即是说,如果同时出现了Module和祖先Class,那么程序将先到Module中寻找。那么如果祖先Class也含有这个Module又会是怎么样的状况呢?

module M 
  def a 
    p 'M a 1'
  end
end

class B
  def a
    p 'B a 1'
    super
    p 'B a END'
  end
  include M
end

class A < B
  include M
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

 输出结果:

Output 写道
:!ruby method01.rb
"a 2"
"B a 1"
"M a 1"
"B a END"
"a 2 END"

 如果将Module混入它的祖先,那么这个层次结构又发生了变化:

类层次结构 写道
A<B<M

 也就是说如果“老子”和“小子”都想有“XXX”,那么这个“XXX”肯定是归“老子”的了,毕竟“小子”得懂得孝道,不光中国是这样,在日本也是这样的文化吧。

下面我们来讨论一下,这个调用super是否把参数也传进去了呢?

在《Ruby For Rails》中有这样一段描述:

super的参数传递 写道
以裸词super调用祖先/模块方法(callee),则将传递调用者(caller)的全部方法参数;
以super()调用,则不会传递caller的任何参数;
以super(a,b)调用,则将传递部分参数a、b.

 我们仍然以一个例子来看看效果:

module M 
  def a(x=5,y=6) 
    p 'M a 1'
    p x
    p y
  end
end

class B
  def a(x=3,y=4)
    p 'B a 1'
    p x
    p y
    super(x)
    p 'B a END'
  end
  include M
end

class A < B
  include M
  def a
    p 'a 1'
  end
  def a(x=1,y=2)
    p 'a 2'
    p x
    p y
    super
    p 'a 2 END'
    super()
  end
end

b = A.new
b.a(-1,-2)

 输出结果:

Output 写道
:!ruby method01.rb
"a 2"
-1
-2

"B a 1"
-1
-2

"M a 1"
-1
6
"B a END"
"a 2 END"
"B a 1"
3
4

"M a 1"
3
6
"B a END"

 果然,确实是有不同的效果。不过在使用super()super(a) 时,需要注意由于参数数据不全原方法需要是默认参数值的

最后,我给出一个综合的实例吧:

 

里面有很多错误和冗余,希望大家可以先自己看看输出结果然后再看实际结果,你们会有更多的收获的:

module M
  def report( a = 4, b =5)
    p "M report begin: a=#{a},b=#{b}"
    a = 6
    super(a)
    p "M report end"
  end
end

class B
  def report(a=11,b=12)
    p "B report 1 begin: a=#{a},b=#{b}"
    p "B report 1 end"
  end
  def report(a=13,b=14)
    p "B report 2 begin: a=#{a},b=#{b}"
    #super
    p "B report 2 end"
  end
end

class C < B
  def report( a=8,b=9)
    p "C report 1 begin: a=#{a},b=#{b}"
    p "C report 1 end"
  end
  def report( a=7,b=3)
    p "C report 2 begin: a =#{a},b=#{b}"
    super()
    p "C report 2 End"
  end
  include M
end

class D < C
  def report( a = 2, b=1)
    p "D report 1 begin: a=#{a},b=#{b}"
    super(a,b)
    p "D report 1 end"
  end
  include M
  def report(a = -2, b=-1)
    p "D report 2 begin: a=#{a},b=#{b}"
    super
    p "D report 2 end"
  end
end

d = D.new
d.report

 输出结果:

Output 写道
"D report 2 begin: a=-2,b=-1 "
"C report 2 begin: a =-2,b=-1 "
"M report begin: a=4,b=5 "
"B report 2 begin: a=6,b=14 "
"B report 2 end"
"M report end"
"C report 2 End"
"D report 2 end"

 通过实例,大家应该可以比较清晰的了解method查找调用规律和具体的super使用了。

现在做以下总结:

  • 同一个class和module中,重复声明一个method只有一个有效(用super也无法调用“过时”的几个);
  • 一般过程是:本实例对象的方法体-->本对象对应类的方法体-->本对象包含的module(保证祖先那里没有include)-->祖先-(递归的)->......
  • super传递参数有三种(裸词、空、部分)
  • 不要写这种很难懂的方法结构
分享到:
评论

相关推荐

    Ruby 基础

    Ruby支持块(block),这是匿名函数的一种形式,通常与`yield`关键字一起使用。块可以用`do..end`或`{..}`定义,并且可以接受参数。 面向对象编程是Ruby的核心。Ruby中的每个对象都是一个类的实例,每个类都继承自`...

    函数重写.rar

    在Ruby中,可以通过在子类中定义同名方法并调用`super`关键字来实现。`super`关键字用于调用父类中的同名方法,这样可以在子类的方法中添加额外的功能,同时保留父类原有的功能。这种方式称为方法的组合,它允许我们...

    Ruby 学习指南.rar

    - 函数与方法:Ruby中函数和方法是一体的,可以使用`def`定义,支持参数传递、默认参数、rest参数和block参数。 2. **面向对象编程** - 类与对象:Ruby是纯面向对象的语言,一切皆对象,通过`class`定义类,`new`...

    Ruby语言相关项目的示例

    - Proc和Lambda是Ruby中的匿名函数,它们可以捕获当前上下文,Proc更宽松,Lambda更严格,遵循函数调用规则。 5. **元编程** - Ruby的元编程能力强大,可以在运行时修改类和对象的行为。 - `class_eval`和`...

    Ruby course

    ### Ruby的对象与方法调用 #### 一切皆对象 Ruby的一个核心特性是一切皆对象。这意味着无论是数字、字符串还是其他数据类型,在Ruby中都可以视为对象,并且可以调用它们的方法。例如: ```ruby (5.6).round # 输出 ...

    Ruby语言中文教程

    Ruby中的类还可以继承,通过`操作符定义子类,并可以使用`super`关键字调用父类的方法。 三、控制结构 Ruby提供了多种控制结构,如条件语句(if/else, case)、循环(for, while, until, each)和流程控制语句...

    ruby——course.pdf

    Ruby中的函数定义使用`def`关键字,其语法与许多其他编程语言相似。函数可以接受参数,并且在函数体内部可以通过`return`语句返回值。例如,下面的代码展示了如何定义一个简单的函数`hello`,该函数接受一个参数`...

    ruby简单笔记

    例如,在`Student`类中,`Person`作为其基类,`Student`必须调用`super`以执行`Person`的初始化过程。 #### 八、实例变量与类方法 实例变量以`@`开头,用于存储特定对象的状态。类方法则以`class 的形式定义,允许...

    Ruby Source Code

    例如,`class MyClass`定义一个新类,`super`关键字用于调用父类的方法,`attr_accessor`则用于快速创建getter和setter方法。 2. **动态性**:Ruby允许在运行时改变对象的属性和行为。这通过其灵活的数据类型、变量...

    Ruby程序设计(简洁清新的教程)

    Ruby支持动态方法定义和调用,以及元编程能力: ```ruby def MyClass.my_method puts "This is a dynamic method." end MyClass.my_method ``` **3.8 变量** - **局部变量**:作用域限制在定义它的方法内部。 -...

    Ruby程序设计(word文档).zip

    类可以继承其他类,使用`super`调用父类方法,以及实现多重继承和模块混合(Mix-in)。 5. **模块**:模块用于代码复用和分类,可以通过`include`或`prepend`引入到类中,提供命名空间隔离和防止命名冲突。 6. **...

    prototype_oop_javascript_ruby_prototype_

    Ruby中,类通过继承来扩展功能,可以使用`super`关键字调用父类的方法。同时,Ruby支持模块(Module),可以用来实现类似于JavaScript原型的混入(Mix-in)行为: ```ruby module Sayable def say_hello puts '...

    利用Ruby的SOAP4R编写SOAP服务器的教程

    super(*args) add_method(self, 'add', %w(in a), %w(in b)) add_method(self, 'div', %w(in a), %w(in b)) end end ``` 这里`add_method`的第一个参数是接收者(self),第二个参数是方法名,之后的参数分别...

    Ruby

    3. **块(Blocks)和 Proc**:Ruby中的块是代码段,可以与方法一起使用,通过`do..end`或`{..}`定义。Proc是可存储的块,可以赋值给变量,作为参数传递或作为返回值。 4. **闭包(Closures)**:Ruby的Proc和Lambda...

    Ruby学习思维导图.pdf

    - **super**:调用父类的同名方法。 **2.3 模块** - **模块定义**:使用 `module` 关键字定义模块。 - **混入模块**:通过 `include` 或 `extend` 将模块的功能添加到类或对象中。 **2.4 元编程** - **define_...

    Curso-Basico-Ruby

    你可以使用`new`关键字实例化对象,`super`关键字调用父类的方法。 5. **模块(Module)** 模块是Ruby中实现代码重用的一种方式,可以包含常量、方法和类。通过`include`或`extend`,可以让一个类导入模块中的成员...

    袍:Ruby的代码导航,文档查找和完成

    跳到super或在点处调用的构造函数 跳转到模块/类/常量定义 显示方法文档 显示有关使用ElDoc在点调用的方法的信息 方法和常量名称完成 使用简单的正则表达式搜索在当前文件中跳转和完成实例和本地变量名 要查看可用...

    LittleBookOfRuby

    - **super关键字**:调用父类方法的机制。 #### 5. 类变量 - **类变量作用域**:一种特殊的变量类型,可在类的所有实例间共享。 ### 第五部分:数组 #### 1. 数组使用 - **数组创建**:创建数组的各种方式。 - **...

    初步了解一下什么是ruby

    - `super` 调用父类的方法。 - `self` 引用当前对象自身。 4. **嵌入模块和块**: - `BEGIN` 和 `END` 用于在程序开始和结束时执行代码。 - `begin` 和 `end` 用于定义代码块。 5. **文件相关**: - `_FILE_`...

Global site tag (gtag.js) - Google Analytics