我在这里读过其他相同的question,但是对于某些内置类来说,这种情况太具体了。我想在这里问一个简单的案例,并希望得到一般的答案。
所以我有这段代码:
object ScalaApp {
case class Point(x: Int, y: Int);
case class Rational(n: Int, d: Int) {
def \(i: Int): List[Int] = n :: d:: i :: Nil
}
case class MyObject(x: Int, y: Int, z: Int) {
def \(i: Int): List[Int] = x :: y:: i :: Nil
}
implicit def pointToRational(p: Point): Rational = Rational(p.x + 1, p.y * 2)
implicit def pointToMyObject(p: Point): MyObject = MyObject(p.x, p.y, p.x+p.y)
def main(args: Array[String]) {
val p = Point(5, 7)
val result = p \ 6 // compile error here
}
}
我们可以看到将p
应用于\
方法时发生错误,然后触发隐式转换。 Scala编译器将尝试查找已定义def \(i: Int)
方法的任何导入或本地类。如果找到,那么它将尝试查找采用Point
类型的任何隐式转换方法,并返回具有def \(i: Int)
方法签名的对象类型。
有两个类在def \
和Rational
有MyObject
方法,并且有两个隐式方法:pointToRational
和pointToMyObject
对于这两个班级。
但是由于Rational
和MyObject
都定义了def \
,因此发生了模糊的编译错误,因为它无法决定应采用哪一个。
Error:(30, 22) type mismatch;
found : p.type (with underlying type ScalaApp.Point)
required: ?{def \(x$1: ? >: Int(6)): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method pointToRational in object ScalaApp of type (p: ScalaApp.Point)ScalaApp.Rational
and method pointToObj in object ScalaApp of type (p: ScalaApp.Point)ScalaApp.MyObject
are possible conversion functions from p.type to ?{def \(x$1: ? >: Int(6)): ?}
val result = p \ 6
^
所以我的问题是,有没有办法解决模糊的隐式错误,但仍保留两个def \
方法或不删除隐式转换方法之一?
答案 0 :(得分:4)
你可以这样做:
scala> val result = (p: Rational) \ 6
result: List[Int] = List(6, 14, 6)
scala> val result = (p: MyObject) \ 6
result: List[Int] = List(5, 7, 6)
所以你可以把它放在代码中而不是:
val result = p \ 6 // compile error here
它将你的暗示转移到单独的对象的另一种方式:
object Implicits {
implicit def pointToRational(p: Point): Rational = Rational(p.x + 1, p.y * 2)
implicit def pointToMyObject(p: Point): MyObject = MyObject(p.x, p.y, p.x+p.y)
}
def main(args: Array[String]) {
val p = Point(5, 7)
import Implicits.pointToMyObject
val result = p \ 6
}
答案 1 :(得分:1)
不是真的。您有时可以滥用implicit resolution order(例如,通过将其中一个隐含移动到伴随对象或伴随对象扩展的特征,以便仅在查找直接范围内的隐含之后查看它)。但一般来说,你应该只确保在范围内只有一个合适的隐含。请记住,您始终可以使用{}
创建内部范围,并在该范围内导入隐式范围:
val result = {import someImplicit; p \ 6}