在Scala中,是否可以向内置类型添加方法?

11

我想在内置类型(例如Double)中添加一个方法,以便可以使用一个 infix 运算符。这是否可能?

2个回答

19

是和不是。是的,你可以让它看起来像你已经向double添加了一个方法。例如:

class MyRichDouble(d: Double) {
  def <>(other: Double) = d != other
}

implicit def doubleToSyntax(d: Double) = new MyRichDouble(d)

这段代码将在任何Double类型的对象中添加之前不可用的<>运算符。只要doubleToSyntax方法处于范围内,以便可以无需限定调用它,以下内容将起作用:

3.1415 <> 2.68     // => true
"no"的答案来源于您并没有真正地向Double类中添加任何内容。相反,您正在创建一种从Double到新类型的转换,该新类型定义了所需方法。这可以比许多动态语言提供的开放类技术更为强大。它也是完全类型安全的。 :-)
您应该注意以下一些限制:
  • 此技术不允许您删除或重新定义现有方法,只能添加新方法
  • 隐式转换方法(在此示例中为doubleToSyntax)必须绑定在所需扩展方法的范围内才能使用
习惯上,隐式转换要么放在单例对象中并导入(例如,import Predef._),要么放在特质中并被继承(例如,class MyStuff extends PredefTrait)。
稍微偏离一下话题: 在Scala中,“中置操作符”实际上是方法。 <> 方法并没有与之相关的神奇功能,解析器只是以那种方式接受它。 如果您喜欢,也可以将“常规方法”用作中缀运算符。 例如,Stream类定义了一个take方法,它接受一个Int参数并返回一个新的Stream。 可以按以下方式使用它: "
val str: Stream[Int] = ...
val subStream = str take 5

str take 5表达式与str.take(5)完全相同。


你可以使用 implicit class 语法来简化这个过程。 - lmm

2

这个功能非常有用,可以实现一个执行错误估计的类:

object errorEstimation {
  class Estimate(val x: Double, val e: Double) {
    def + (that: Estimate) =
      new Estimate(this.x + that.x, this.e + that.e)
    def - (that: Estimate) =
      new Estimate(this.x - that.x, this.e + that.e)
    def * (that: Estimate) =
      new Estimate(this.x * that.x,
                   this.x.abs*that.e+that.x.abs*this.e+this.e*that.e)
    def / (that: Estimate) =
      new Estimate(this.x/that.x,
                   (this.x.abs*that.e+that.x.abs*this.e)/(that.x.abs*(that.x.abs-that.e)))
    def +- (e2: Double) =
      new Estimate(x,e+e2)
    override def toString =
      x + " +- " + e
  }
  implicit def double2estimate(x: Double): Estimate = new Estimate(x,0)
  implicit def int2estimate(x: Int): Estimate = new Estimate(x,0)

  def main(args: Array[String]) = {
    println(((x: Estimate) => x+2*x+3*x*x)(1 +- 0.1))
    // 6.0 +- 0.93
    println(((x: Estimate) => (((y: Estimate) => y*y + 2)(x+x)))(1 +- 0.1))
    // 6.0 +- 0.84
    def poly(x: Estimate) = x+2*x+3/(x*x)
    println(poly(3.0 +- 0.1))
    // 9.33333 +- 0.3242352
    println(poly(30271.3 +- 0.0001))
    // 90813.9 +- 0.0003
    println(((x: Estimate) => poly(x*x))(3 +- 1.0))
    // 27.037 +- 20.931
  }
}

那其实挺不错的。 :) - Marcus Downing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接