文章

💎 Ruby 方法转换成方法对象

介绍如何将 Ruby 中的方法转换成方法对象,并展示其用法

在 Ruby 中,方法自身不是对象,但可以通过对象化操作将其转换为对象。以下是一些关于如何将方法转换成方法对象的详细说明。

对象化操作

可以使用 unbound() 对一个 Method 对象进行解绑,然后再用 bind(obj1) 绑定到另一个对象 obj1 上,obj1 可以是同类对象或子类对象。

示例代码

以下是一个示例,演示如何将方法转换成方法对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class C
  attr_accessor :name

  def talk
    puts "say hello: #{self.name}"
  end
end

c = C.new
d = C.new
c.name = "cccc"
d.name = "dddd"

c_meth = c.method(:talk) # 绑定在对象c上
p c_meth     # #<Method: C#talk>

unmeth = c_meth.unbind  # 从对象c上解绑
p unmeth     # #<UnboundMethod: C#talk>

d_meth = unmeth.bind(d)  # 绑定到对象d上
p d_meth     # #<Method: C#talk>
d_meth.call  # say hello: dddd

使用 instance_method

可以直接在类上使用 instance_method() 类方法返回该类的一个未绑定的 Method 对象。这等价于先绑定在一个对象上,再从这个对象上解绑:

1
2
unmeth1 = C.instance_method(:talk)
p unmeth1    # #<UnboundMethod: C#talk>

未绑定方法的奇效

得到一个未绑定的方法有时会产生意想不到的效果。例如,在子类对象上直接调用某个方法时,它只会执行第一个查找到的方法。如果想要明确执行父类或某个层次的祖先类中的同名方法,这时只能通过未绑定方法来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A
  def talk
    puts "I am A"
  end
end

class B < A
  def talk
    puts "I am B"
  end
end

class C < B
end

c = C.new
c.talk  # 调用的父类B中的talk
meth = A.instance_method(:talk)
meth.bind(c).call  # 输出 "I am A"

总结

通过将方法转换为方法对象,您可以灵活地操作和调用方法,尤其是在涉及多层继承时,能够精确控制调用哪个类中的方法。此特性在 Ruby 中使得方法处理更加灵活。

本文由作者按照 CC BY 4.0 进行授权