less than 1 minute read

在 Ruby 中如何给一个已经存在的类添加新的方法?

例如,我们希望给整数添加 is_even?is_odd? 方法,用来判断一个整数是否为偶数或者奇数。

3.is_even? # false
3.is_odd?  # true

在 Scala 中,我们可以使用 extension 关键字来实现,类似这样:

extension (n: Int)
  def isEven = n % 2 == 0
  def isOdd  = n % 2 != 0

3.isEven // false
3.isOdd  // true

在 Scala 2 中,我们使用 implicit class 来实现:

implicit class IntOps(n: Int) {
  def isEven = n % 2 == 0
  def isOdd  = n % 2 != 0
}

编译时的代码类似这样:

// 3.isEven
IntOps(3).isEven
// 3.isOdd
IntOps(3).isOdd

可以看到,Scala 的实现原理是对原类进行包装,再通过包装类扩展方法。

与 Scala 不同,在 Ruby 中,我们不需要对类进行包装,而是可以直接扩展已有类:

class Integer
  def is_even? = self % 2 == 0
  def is_odd?  = self % 2 != 0
end

方法体中的 self 关键字指代当前调用该方法的对象实例。

方法名中的 ? 表示这个方法返回一个布尔值

在 Ruby 社区中通常将这种手法称作打开类(Open Class),或者猴子补丁(Monkey Patch),是一种在运行时修改类的行为的一种方法。

运行时的代码类似这样:

# 3.is_even?
3.send(:is_even?)
# 3.is_odd?
3.send(:is_odd?)

Tags:

Categories:

Updated: