锁定老帖子 主题:Ruby的函数调用与super
精华帖 (0) :: 良好帖 (0) :: 新手帖 (3) :: 隐藏帖 (7)
|
|
---|---|
作者 | 正文 |
发表时间:2008-11-22
最近在巩固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使用了。 现在做以下总结:
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 2256 次