当我尝试编译以下代码时
case class A(x: Int = 0)
object Conversions {
case class Converter[T](c: T) {
def +[U](that: Converter[U]): String = "worked"
}
implicit def convert(c: A): Converter[A] = Converter[A](c)
implicit def convert(c: Int): Converter[Int] = Converter[Int](c)
}
object Main extends App {
import Conversions._
val a: String = A() + A()
val b: String = 1 + A() // FAIL
val c: String = A() + 1
val d: Int = 1 + 1
}
我收到以下错误消息
错误:类型不匹配;找一个; required:String
Int
和A
之间有什么区别,因此b
和a
传递时表达式c
失败了?我该怎么做才能编译?
答案 0 :(得分:1)
首先,差异是Int
已经有另一个+
方法,它需要另一个Int
并返回Int
;
如果您向A
添加类似的方法,则会遇到类似的失败:
case class A(x: Int = 0) {
// this would be similar to Int's plus operation:
def +(other: A): A = A(x + other.x)
}
// now these would behave "symmetrically":
val a: A = A() + A()
val b: String = 1 + A() // FAIL
val c: String = A() + 1 // FAIL
val d: Int = 1 + 1
至于为什么这个事实导致了这个特定的失败 - 这更棘手,我认为它与编译器试图选择"选择"的顺序有关。基于左右参数的正确隐式转换。
答案 1 :(得分:0)
如果您将算术+
运算符替换为plus
:
def plus[U](that: Converter[U]): String = "worked"
您的隐式转化应该按预期方式运行:
val a = A() plus A() // worked
val b = 1 plus A() // worked
val c = A() plus 1 // worked
val d = 1 plus 1 // worked
而不是Int
和A
之间的直接隐式转换,您的隐式转换介于Int
和类Converter
之间(以及A
和{之间{1}})。当编译器看到Converter
为Int
定义良好的方法时,显然很难对A
和+
之间的转换规则进行排序 - 除非您提供直接隐式Int
和Int
之间的转换,如下例所示:
A
答案 2 :(得分:0)
我对此尝试成功的原因并不清楚,但我希望它对其他用户有用。在这里,我同时匹配两个参数,以尽量减少Scala强制纠正隐式转换树的尝试。
object Defs {
case class A(x: Int = 1)
case class B(x: Int = 2)
trait IsExpr[T] {
def conv(v: T): Int
}
implicit object aIsExpr extends IsExpr[A] {
override def conv(v: A): Int = v.x
}
implicit object bIsExpr extends IsExpr[B] {
override def conv(v: B): Int = v.x
}
implicit def canSum1[A, B](a: A, b: B)(implicit ca: IsExpr[A], cb: IsExpr[B]): Int = ca.conv(a) + cb.conv(b)
implicit def canSum2[A](a: A, b: Int)(implicit ca: IsExpr[A]): Int = ca.conv(a) + b
implicit def canSum3[A](a: Int, b: A)(implicit ca: IsExpr[A]): Int = a + ca.conv(b)
implicit def convert[A](a: A) = new {
def +[B](b: B)(implicit f: (A, B) => Int): Int = f(a, b)
}
}
object Main extends App {
import Defs._
val a: Int = A() + A()
val b: Int = 1 + A()
val c: Int = A() + 1
val d: Int = 1 + 1
}