RSS

Monthly Archives: April 2011

Ruby中重复定义的方法

“正在因你的调用语句而执行的方法,就真的是你期望着被执行的那一个实现吗?” 偶然的一次merge为我的ruby代码带来一个有趣的问题。

相同签名的方法

1)Ruby类中赤裸裸地出现两个签名一致的方法,被调用时不会报告错误的。同层级的多个相同签名的方法,被认可、被调用的是最后一处定义。

class TestMethodCalling
  def say_hello
    puts "hello, I'am the implementation 1."
  end
 
  def say_hello
    puts "hello, I'am the implementation 2."
  end
end

instance = TestMethodCalling.new
instance.say_hello

----------------
> hello, I'am the implementation 2.

2)Ruby子类中可直接重复定义父类中的已有方法,子类方法被调用。

class SuperClass
  def say_hello
    puts "hello, I'am the implementation 4."
  end
end

class TestMethodCalling < SuperClass
  def say_hello
    puts "hello, I'am the implementation 1."
  end
end

instance = TestMethodCalling.new
instance.say_hello

----------------
> hello, I'am the implementation 1.

3)通过Mix’in的方式将Module的方法引入类中,类中方法被优先调用。

module SayingModule
  def say_hello
    puts "hello, I'am the implementation 3."
  end
end

class TestMethodCalling
  include SayingModule
  def say_hello
    puts "hello, I'am the implementation 1."
  end
end

instance = TestMethodCalling.new
instance.say_hello

----------------
> hello, I'am the implementation 1.

4)通过Mix‘in的方式将Module的方法引入子类中,子类中并无方法定义,但父类中有,Module方法被调用。

module SayingModule
  def say_hello
    puts "hello, I'am the implementation 3."
  end
end

class SuperClass
  def say_hello
    puts "hello, I'am the implementation 4."
  end
end

class TestMethodCalling < SuperClass
  include SayingModule
end

instance = TestMethodCalling.new
instance.say_hello

----------------
> hello, I'am the implementation 3.

5)被调用方法未定义时,Ruby仍能包容,它会寻找method_missing(method_name)方法并调用,其中method_name是被调用方法名称;若找不到,那么才报出undefined method错误。

class TestMethodCalling
  def method_missing(m)
    puts "missing method name is '#{m}'."
  end
end

instance = TestMethodCalling.new
instance.not_existing_method

----------------
> missing method name is 'not_existing_method'.

小结
Ruby解释执行方法的调用时,会按照current class ->Module ->parent class的优先顺序寻找方法定义;当在同一层级下遇到多处相同签名的方法定义时,执行最后一个。

重复名称的class/module

Ruby不止对方法定义和调用展现其包容性,对待类和module也能如此。

1)对类和module而言,分散在多处的同名称定义可看作该类或module的各个组成部分,实例变量的作用域贯穿各处的方法定义。

2)有多处同名的类定义或module定义时,签名相同的方法被执行的仍是最后一处。当这些定义不在同一个文件中时,会按照require文件的顺序中的最后一处选择。

module SayingModule
  def say_yes
    puts "Yes, sir. I'am in the module. #{@me}"
  end
end

class SuperClass
  def say_hello
    puts "hello, I'am in super class."
  end
end

class TestMethodCalling < SuperClass 
  def say_hello
    puts "hello, I'am the implementation 1."
  end
 
  def say_bye
    puts "Bye, I'am the implementation 1. #{@me}"
  end
end

class TestMethodCalling < SuperClass
  def say_hello
    @me = "shaobo"
    puts "hello, I'am the implementation 2.1. #{@me}"
  end

  include SayingModule
end

instance = TestMethodCalling.new
instance.say_hello
instance.say_yes
instance.say_bye

----------------
> hello, I'am the implementation 2.1. shaobo
> Yes, sir. I'am in the module. shaobo
> Bye, I'am the implementation 1. shaobo

不得不承认Ruby太开放了,动态解释的强大包容力是在编译型语言里想都想不到的。

Java说,相同签名的方法不能同时存在在一个类里;
C#说,子类里复写父类的方法要加关键字;
C++说,继承了多个父类后,使用声明相同的父类成员时要指明用哪个父类的;
⋯⋯
Ruby说,你们那些都是浮云,在我这儿没那么多规矩。

 
Comments Off on Ruby中重复定义的方法

Posted by in Uncategorized

 

Tags: