Scala隐式转换函数名称冲突
我正在Scala中使用一个简单的复数case类,并希望创建一个在复数、double和int之间工作的add函数。下面是一个简单的工作解决方案示例: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
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+。