Scala 操作符重载,将左手参数作为内置参数。

10 浏览
0 Comments

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类型的参数。有没有办法让我写这个并按照我想要的方式工作?

我已经了解了右结合方法,但它们似乎需要不同的运算符名称。

admin 更改状态以发布 2023年5月20日
0
0 Comments

使用隐式转换将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,因此您将会得到所有浮点比较的通常的挫败感和意外行为
0
0 Comments

您可以将Int转换为Complex进行隐式转换:

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

您可以了解有关隐式的信息(例如:在此处:Understanding implicit in Scala)。简而言之,如果您的程序无法进行类型检查,则会尝试当前范围内所有隐式转换,如果其中一些工作,则编译器将应用它们。

因此,当您编写2 + c时,编译器找不到接受Int中的复杂数量的+运算符,因此它会尝试隐式转换。然后它将编译2 + cintToComplex(2) + c,这将正确工作。

0