Scala隐式转换函数名称冲突

Scala隐式转换函数名称冲突,scala,implicit-conversion,Scala,Implicit Conversion,我正在Scala中使用一个简单的复数case类,并希望创建一个在复数、double和int之间工作的add函数。下面是一个简单的工作解决方案示例: case class Complex(re: Double, im: Double) implicit def toComplex[A](n: A)(implicit f: A => Double): Complex = Complex(n, 0) implicit class NumberWithAdd[A](n: A)(implici

我正在Scala中使用一个简单的复数case类,并希望创建一个在复数、double和int之间工作的add函数。下面是一个简单的工作解决方案示例:

case class Complex(re: Double, im: Double) 

implicit def toComplex[A](n: A)(implicit f: A => Double): Complex = Complex(n, 0)

implicit class NumberWithAdd[A](n: A)(implicit f: A => Complex) {
    def add(m: Complex) = Complex(n.re + m.re, n.im + m.im)
}
注意,我故意不在complexcase类中包含add函数。使用上述方法,我可以完成所有这些:

scala> val z = Complex(1, 2); val w = Complex(2, 3)
z: Complex = Complex(1.0,2.0)
w: Complex = Complex(2.0,3.0)

scala> z add w
res5: Complex = Complex(3.0,5.0)

scala> z add 1
res6: Complex = Complex(2.0,2.0)

scala> 1 add z
res7: Complex = Complex(2.0,2.0)
我想使用“+”而不是“add”,但是这不起作用。我得到以下错误:

Error:(14, 4) value + is not a member of A$A288.this.Complex
              z + 1
               ^
然而,
z+w
1+z
仍然有效

我想知道的是,为什么将函数名从“add”更改为“+”会破坏这一点?是否有其他途径获得此功能(而不只是将add函数放在复杂的case类中)?任何帮助都将不胜感激

编辑动机 我在玩弄幺半群和其他代数结构。我希望能够将“…WithAdd”函数推广为自动适用于具有相应幺半群的任何类:

trait Monoid[A] {
    val identity: A

    def op(x: A, y: A): A
}

implicit class withOp[A](n: A)(implicit val monoid: Monoid[A]) {
    def +(m: A): A = monoid.op(n, m)
}

case class Complex(re: Double, im: Double) {
    override def toString: String = re + " + " + im + "i"
}

class ComplexMonoid extends Monoid[Complex] {
    val identity = Complex(0, 0)

    def op(z: Complex, w: Complex): Complex = {
        Complex(z.re + w.re, z.im + w.im)
    }
}

implicit val complexMonoid = new ComplexMonoid

使用上面的代码,我现在可以做
Complex(1,2)+Complex(3,1)
给出
Complex=4.0+3.0i
。这对于代码重用是非常好的,因为我现在可以向Monoid和withAdd函数添加额外的函数(例如对元素应用op n次,为乘法提供幂函数),并且它适用于具有相应Monoid的任何case类。只有使用复数并尝试合并双精度、整数等,我才会遇到上述问题。

我会使用常规的
类,而不是
案例类。然后就可以很容易地创建添加或减去这些复数的方法,如:

class Complex(val real : Double, val imag : Double) {

  def +(that: Complex) =
            new Complex(this.real + that.real, this.imag + that.imag)

  def -(that: Complex) =
            new Complex(this.real - that.real, this.imag - that.imag)

  override def toString = real + " + " + imag + "i"

}
如图所示,它现在将支持类似于运算符重载的内容(不是,因为
+
-
是函数而不是运算符)

隐式类numberwhithadd
及其方法
+
的问题在于,在诸如
Int
Double
等数字类中也存在相同的方法。
+
方法的
NumberWithAdd
基本上允许您从一个可以转换为
Complex
的数字开始,并向第一项添加一个
Complex
对象。也就是说,左侧值可以是任何值(只要可以转换),右侧值必须是复杂的

这对于
w+z
(无需转换
w
)和
1+z
(可以将
Int
隐式转换为
复杂的
)。对于
z+1
,它失败,因为
+
在类
复合体中不可用。
由于
z+1
实际上是
z.+(1)
,Scala将在
复杂的
可以转换成的类中查找
+(i:Int)
的其他可能匹配项。它还使用add
检查
编号,add确实具有
+
功能,但该功能需要一个
复数
作为右侧值。(它将匹配一个需要
Int
作为右手值的函数。)还有其他名为
+
的函数确实接受
Int
,但没有从
复数
转换为这些函数想要的左手值

+
的相同定义在(case)类
Complex
中也适用。在这种情况下,
w+z
z+1
都使用该定义。案例
1+z
现在稍微复杂一些。由于
Int
没有接受
Complex
值的函数
+
,Scala将在
Complex
中找到接受该值的函数,并确定是否可以将
Int
转换为
Complex
。这可以使用隐式函数进行转换并执行函数

当类
numberwhithadd
中的函数
+
重命名为
add
时,不会与
Int
中的函数混淆,因为
Int
没有函数
+
。因此,Scala将更努力地应用函数
add
,并将
Int
转换为
复数。当您尝试添加2时,它甚至会进行转换


注意:我的解释可能无法完全描述实际的内部工作。

我知道这是一个解决方案,但我在问题中提到,我不希望case类中包含函数。我的部分问题是,是否有其他方法可以做到这一点。@Tom我已经扩展了我的答案。这将有望进一步澄清问题。因此,如果我们不/不能修改
类Complex
,那么我们需要做的就是将
z+1
添加到
def+(i:Int):Complex=this.+(toComplex(i))
NumberWithAdd
类中。但这只包括
z+1
(Int)。我们必须添加同样的内容来涵盖
z+1L
(长)和
z+1.1
(双),等等。*叹气*@Arjan感谢您花时间充实您的答案。似乎得到一个不同的解决方案比我想象的要困难得多。@jwvh我想像
Int
Double
这样的类有几个函数
+
,它们都接受不同的参数(并且有不同的返回类型),这是有原因的。无法添加已通过隐式转换存在的方法。您链接到的问题是试图隐式重写具有相同签名的函数。Int、Double或my Complex类型的类都没有一个带有一个Complex类型参数的method+。