Tom*_*Tom 6 scala implicit-conversion
我正在使用Scala中一个简单的复数案例类,并希望创建一个在复数,双精度和整数之间工作的加法函数.以下是工作解决方案的简单示例:
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)
}
Run Code Online (Sandbox Code Playgroud)
注意我故意不在复杂的case类中包含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)
Run Code Online (Sandbox Code Playgroud)
我想使用'+'而不是'add,但是这不起作用.我收到以下错误:
Error:(14, 4) value + is not a member of A$A288.this.Complex
z + 1
^
Run Code Online (Sandbox Code Playgroud)
双方z + w并1 + z不过仍然可以工作.
我想知道的是为什么将函数名称从'add'改为'+'会打破这个?是否有另一种获得此功能的途径(不需要简单地将add函数放在复杂的case类中)?任何帮助,将不胜感激.
我正在玩幺半群和其他代数结构.我希望能够概括'... WithAdd'函数自动适用于任何具有相应monoid的类:
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
Run Code Online (Sandbox Code Playgroud)
使用上面我现在可以Complex(1, 2) + Complex(3, 1)给予Complex = 4.0 + 3.0i.这对于代码重用非常有用,因为我现在可以向Monoid和withAdd函数添加额外的函数(例如,将元素应用于元素,给出乘法的幂函数),它适用于任何具有相应的monoid的case类.它只是复杂的数字并试图合并双打,整数等,然后我遇到上面的问题.
我会使用常规的class,而不是case class. 然后很容易创建方法来添加或减去这些复数,例如:
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"
}
Run Code Online (Sandbox Code Playgroud)
正如源页面所示,它现在将支持看起来像运算符重载的东西(它不是,因为+和-是函数而不是运算符)。
implicit class NumberWithAdd和的方法的问题+在于,相同的方法也存在于数字类中,例如Int和Double。+的方法基本上NumberWithAdd允许您从一个可以转换的数字开始Complex,并将一个Complex对象添加到第一个项目。也就是说,左手值可以是任何值(只要可以转换),右手值必须是Complex。
这非常适合w + z(无需转换w) 和(可以使用to 的1 + z隐式转换)。它失败是因为在类中不可用。由于实际上是,Scala 将寻找可转换为的类中的其他可能匹配项。它还检查,它确实有一个函数,但需要 a作为右手值。(它将匹配需要右手值的函数。)还有其他名为接受的函数,但没有从这些函数想要的左手值进行转换。IntComplexz + 1+Complexz + 1z.+(1)+(i: Int)ComplexNumberWithAdd+ComplexInt+IntComplex
当它在 (case) class 中时,相同的定义确实+有效Complex。在这种情况下, 和w + z都z + 1简单地使用该定义。现在案件1 + z有点复杂了。由于Int没有+接受Complex值的函数,Scala 将找到接受值的函数 (in Complex) 并确定是否可以转换Int为Complex. 使用隐式函数可以实现这一点,进行转换并执行函数。
+当类中的函数NumberWithAdd被重命名时add,不会与类中的函数混淆,Int因为类中Int没有函数+。因此 Scala 会更加努力地应用该函数add,并且它将执行InttoComplex转换。当您尝试时它甚至会进行转换1 add 2。
注意:我的解释可能无法完全描述实际的内部工作原理。
| 归档时间: |
|
| 查看次数: |
257 次 |
| 最近记录: |