Scala运算符使用左手参数重载为内置

时间:2014-05-08 16:17:59

标签: scala operator-overloading

我想编写一个可以很好地处理数字和运算符的类,所以我想知道当左手参数是内置类型或其他值时,如何重载运算符,我不能这样做修改实施。

class Complex(val r:Double,val i:Double){
  def +(other:Complex) = new Complex(r+other.r,i+other.i)
  def +(other:Double) = new Complex(r+other,i)
  def ==(other:Complex) = r==other.r && i==other.i
}

通过这个例子,以下工作:

val c = new Complex(3,4)
c+2 == new Complex(5,4)  //true

但我也希望能够写

2+c

不能正常工作Int.+无法接受Complex类型的参数。 有没有办法让我写这个并让它按我的意愿工作?

我发现了正确的关联方法,但它们似乎需要不同的运营商名称。

3 个答案:

答案 0 :(得分:6)

您可以添加从Int到Complex的隐式转换:

implicit def intToComplex(real: Int) = new Complex(real, 0)

您可以阅读有关含义的信息(例如:Understanding implicit in Scala)。简短的版本是,如果你的程序没有进行类型检查,那么将尝试当前作用域中的所有含义,如果其中一些有效,它将由编译器应用。

因此,当您编写2 + c时,编译器找不到在Int中使用复数的运算符+,因此它会尝试隐含。然后它会将2 + c编译为intToComplex(2) + c,这将正常工作。

答案 1 :(得分:3)

如前所述,使用隐式转化将Int转换为Complex即可完成此任务。

这是一个有效的解决方案,它将所有这些放在一起,以补充伊万的答案:

import scala.language.implicitConversions

class Complex(val real:Double, val imaginary:Double){
    def +(other:Complex) = new Complex(real+other.real, imaginary+other.imaginary)
    //def +(other:Double) = new Complex(real+other,imaginary) // Not needed now
    def ==(other:Complex) = real==other.real && imaginary==other.imaginary
    override def toString: String = s"$real + ${imaginary}i"
}

object Complex {
    implicit def intToComplex(real: Int): Complex = doubleToComplex(real.toDouble)
    implicit def doubleToComplex(real: Double): Complex = Complex(real, 0)

    implicit def apply(real: Double, imaginary: Double): Complex = new Complex(real, imaginary)
    implicit def apply(tuple: (Double, Double)): Complex = Complex(tuple._1, tuple._2)

    def main(args: Array[String]) {
        val c1 = Complex(1, 2)
        println(s"c1: $c1")

        val c2: Complex = (3.4, 4.2) // Implicitly convert a 2-tuple
        println(s"c2: $c2")

        val c3 = 2 + c1
        println(s"c3: $c3")

        val c4 = c1 + 2 // The 2 is implicitly converted then complex addition is used
        println(s"c4: $c4")
    }
}

一些注意事项:

  • 在2.10.3下测试。根据您的版本,您可能需要在文件顶部导入。
  • 一旦你进行了隐式转换,你实际上并不需要原始的+方法,它需要Int输入(因此我将其注释掉了)。示例c4证明了这一点。
  • 考虑让您的类具有通用性 - 而不是使用Double,只需使用一些足以满足您需求的数字类型。复数的概念实际上与它扩展的字段/环/组完全分离。例如,如果您的基础类型具有乘法和加法,您也可以为复数定义乘法和加法。
  • 我为Tuple2[Double, Double]类添加了一个隐式转换 - 只是因为它看起来很酷。示例c2演示了它。
  • 同样我添加了apply个方法。请考虑添加unapply方法,使其更加case友好。
  • 我重命名了你的构造函数参数,只是为了让toString方法不那么混乱(所以你没有$ {i} i)
  • 侧面跟踪)您的==方法正在比较类型Double,而不是Int,因此您将获得所有通常的挫折和浮点比较的意外行为

答案 2 :(得分:-1)

来自Scala Reference

的第6.2.3节
  

运算符的关联性由运算符的最后一个字符决定。以冒号结尾的运算符':'是正确联想的。所有其他运算符都是左关联的。

所以你最接近的是2 +: c