ruby中的可调用对象--方法
上一篇讲了ruby中的可调用对象proc和lambda,他们都是块转换成的对象。ruby中的可调用对象还有方法。通过使用method方法,并且以方法名作为参数(字符串或者符号),就可以得到一个方法对象。
如下:
1 class C 2 def talk 3 p "hello world" 4 end 5 end 6 7 c = C.new 8 meth = c.method :talk 9 meth.call
输出: "hello world"
类C有个实例方法talk。类C的实例c调用方法method,并且用:talk做参数,得到一个方法对象meth。然后meth调用call,输出"hello world"。
值得注意的是,meth这个方法对象是绑定在对象c上的方法。调用call的时候,也知道是c在调用talk方法。
可以用Method#unbind()方法来把一个方法跟它绑定的对象相分离,该方法返回一个UnboundMethod对象,不能执行UnboundMethod对象,必须把它绑定到一个对象上,使之再次成为一个Method对象。
如下:(在上面代码的基础上)
1 class D < C 2 end 3 d = D.new 4 unbound = meth.unbind 5 new_meth = unbound.bind(d) 6 new_meth.call
输出: "hello world"
unbind解绑之后,绑定到C的子类D的一个实例对象d上。再对方法对象调用call。如果不想对一个已绑定的方法进行解绑,可以用如下的代码得到解绑对象:
unbound = C.instance_method (:talk)
为什么要这样呢?存在总是合理的,绑定与解绑也有它的适用之处。
在之前《ruby中的方法查找》中,我们知道ruby的方法调用是根据匹配到的第一个方法来调用的。那么如果要调用匹配路径上的匹配到的第二个方法呢?ruby中有super这个关键字。但是加入super关键字相当于改变了这个方法。它并不是直接调用了匹配路径上的第二个方法。而是在匹配到的第一个方法里调用第二个方法。还有,如果要调用匹配路径上的第三个匹配到的方法呢?第四个呢?这个就可以用到绑定的方法了。
如下:
1 class C 2 def method 3 p "this is in C" 4 end 5 end 6 7 class D < C 8 def method 9 p "this is in D" 10 end 11 end 12 13 class E < D 14 def method 15 p "this is in E" 16 end 17 end 18 19 e = E.new 20 e.method 21 22 D.instance_method(:method).bind(e).call 23 C.instance_method(:method).bind(e).call
输出:
"this is in E"
"this is in D"
"this is in C"
如代码所示,定义类C,D,E,D继承C,E继承D。他们都定义了方法method。那么E的实例e的方法查找路径上这三个method都可以调用。如果直接调用e.method。那么肯定是调用了第一个匹配的方法,也就是类E中的方法,如输出的第一行。如果要调用类D中的方法method呢?如代码22行。把D的实例方法绑定到对象e上,然后在调用。调用类C中的方法method,同理。如23行。
学过C++的话,看到这个可能会想到派生类指针引用基类对象。派生类是基类的特例,所以只有强制转换类型之后才能引用基类的对象。和ruby中的绑定类似,只有和父类的方法绑定以后,才能调用父类的方法。
和上一篇一起做一个总结。ruby中可以被调用的对象有:
块(不算是对象,可以被调用),proc(Proc类的对象),lambda(Proc类的对象),这三种都是在定义它们的作用域中执行。
方法:绑定于对象,在所绑定的对象的作用域中执行。
将一种对象转换成另一种对象的方法有:Proc.new(),Method#to_proc(),&操作符