Scala Monkey 补丁与 Ruby 相比

Scala Monkey Patching Compared to Ruby

在 Scala 中你可以使用 implicits 做 Monkey Patching 但昨天我在 ruby 中看到这个例子 wih Fixnum,这是一个愚蠢的事情但我想在 scala 中实现它

class Fixnum

  def to_roman
    'I'*self #only works until 3, but only for this purpose 
  end

   def +(other)
      self - other
   end
end


puts 2.to_roman #This prints "II"
puts 1 + 1 #This prints 0

但是在 scala 中我无法使用 +(逆)方法

object TestImplicits extends App {

  implicit class ReverseInt(val original: Int) extends AnyVal {

    def toRoman = { "I" * original }

    def +(other:Int){
      original - other
    }
  }

  println(5.toRoman) // prints IIIII
  println( 5 + 3 )  // prints 8

}

此外,scala 最好不要像 Ruby 这样的全局猴子补丁?

Scala 只会尝试为未找到的方法寻找隐式转换。由于 Scala 找到了 Int.+ 方法,因此它不会尝试寻找隐式转换,与 toRoman 相反,Scala 不会 找到方法因此将使用 toRoman 方法搜索从 Int 到某种类型的隐式转换。

这很接近:

class WrappedInt(val n: Int) {
  def + (other: Int): Int = {
    n - other
  }
}
implicit def unpack(wi: WrappedInt): Int = {
  wi.n
}

// usage
val wrapped = new WrappedInt(5)
println(wrapped + 3)  // performs 5 - 3
println(wrapped * 2)  // 5 * 2 (`unpack` is called first)

但是请注意,如果将 WrappedInt 传递给需要 Int 的方法,该方法将对展开的值进行操作,因此 "patch" 将不会激活方法内部:

def addOne(n: Int) = {
  n + 1
}
println(addOne(new WrappedInt(5)))  // Prints 6 (no patch)

我认为最好不要允许全局修补 - 这是非常危险的,因为如果您孤立地查看 class,则没有迹象表明某些东西已被修补。项目中的每个人都需要学习和记住所有这些无形中发生的事情。如果您正在处理多个项目,您需要记住哪个项目有哪个补丁。使用 Scala,必须显式导入第三方隐式,因此在当前文件或作用域中有一些迹象表明正在发生一些特殊的事情。

Ruby 进行了改进,但它们 don't seem very popular,可能是因为打补丁非常容易,而且在文化中根深蒂固。