带有左参数的Scala操作符重载是内置的



我想编写一个可以很好地处理数字和操作符的类,所以我想知道当左参数是内置类型或其他无法修改实现的值时,如何重载操作符。

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类型的参数。有没有一种方法可以让我把它写成我想要的样子?

我已经找到了正确的关联方法,但它们似乎需要一个不同的操作符名称

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

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

你可以阅读有关隐式的内容(例如:理解Scala中的隐式)。简而言之,如果你的程序没有类型检查,那么当前作用域中的所有隐式都将被尝试,如果其中一些有效,编译器将应用它。

所以,当你写2 + c时,编译器没有找到一个运算符+,它接受Int的复数,所以它尝试隐式。然后将2 + c编译为intToComplex(2) + c,这将正常工作。

使用前面提到的隐式转换将Int转换为Complex将完成这项工作。

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

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,所以你会得到所有通常的挫折和意想不到的行为与浮点比较

选自Scala参考资料6.2.3节

操作符的结合性由操作符的最后一个字符决定。以冒号":"结尾的操作符是右结合的。所有其他操作符都是左结合的。

所以最接近的是2 +: c

最新更新