简体   繁体   English

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

[英]Is it possible to add a method to a built-in type in Scala?

I would like to add a method to a built-in type (eg Double), so that I can use an infix operator. 我想为内置类型(例如Double)添加一个方法,以便我可以使用中infix运算符。 Is that possible? 那可能吗?

Yes and no. 是的,不是。 Yes, you can make it seem like you have added a method to double . 是的,你可以让它看起来像你添加了一个double的方法。 For example: 例如:

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

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

This code adds the previously-unavailable <> operator to any object of type Double . 此代码将以前不可用的<>运算符添加到Double类型的任何对象。 So long as the doubleToSyntax method is in scope so that it could be invoked without qualification, the following will work: 只要doubleToSyntax方法在范围内,以便可以无限制地调用它,以下将起作用:

3.1415 <> 2.68     // => true

The "no" part of the answer comes from the fact that you aren't really adding anything to the Double class. 答案的“否”部分来自于你并没有真正向Double类添加任何内容。 Instead, you are creating a conversion from Double to a new type which does define the method you want. 相反,您正在创建从Double到新类型的转换,它确定了您想要的方法。 This can be a much more powerful technique than the open-classes offered by many dynamic languages. 这可能是一种比许多动态语言提供的开放类更强大的技术。 It also happens to be completely type-safe. 它也恰好是完全类型安全的。 :-) :-)

Some limitations you should be aware of: 您应该注意的一些限制:

  • This technique does not allow you to remove or redefine existing methods, just add new ones 此技术不允许您删除重新定义现有方法,只需添加新方法即可
  • The implicit conversion method (in this case, doubleToSyntax ) absolutely must be in-scope for the desired extension method to be available 隐式转换方法(在本例中为doubleToSyntax )绝对必须在范围内,以使所需的扩展方法可用

Idiomatically, implicit conversions are either placed within singleton objects and imported (eg import Predef._ ) or within traits and inherited (eg class MyStuff extends PredefTrait ). 在惯用语中,隐式转换要么放在单个对象中并导入(例如import Predef._ ),要么在traits中继承并继承(例如, class MyStuff extends PredefTrait )。

Slight aside: "infix operators" in Scala are actually methods. 稍微说一下:Scala中的“中缀运算符”实际上就是方法。 There is no magic associated with the <> method which allows it to be infix, the parser simply accepts it that way. 没有与<>方法关联的魔法,它允许它作为中缀,解析器只是接受它。 You can also use "regular methods" as infix operators if you like. 如果您愿意,也可以使用“常规方法”作为中缀运算符。 For example, the Stream class defines a take method which takes a single Int parameter and returns a new Stream . 例如, Stream类定义了一个take方法,该方法接受一个Int参数并返回一个新的Stream This can be used in the following way: 这可以通过以下方式使用:

val str: Stream[Int] = ...
val subStream = str take 5

The str take 5 expression is literally identical to str.take(5) . str take 5表达与str.take(5)字面上相同。

This feature came in handy to implement a class performing error estimation: 此功能在实现执行错误估计的类时非常方便:

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
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM