2015-01-10 27 views
2

我在这里读过其他相同的question,但是这种情况对于某些内置类来说太具体了。我想在这里要求简单的案例,并希望得到一般答案。如何解决在Scala中使用相同输入类型的模糊隐式转换方法?

所以我有这样的代码:

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编译器将尝试查找任何已定义方法的导入或本地类。如果找到,那么它将尝试寻找任何类型为Point的隐式转换方法,并返回具有方法签名的对象类型。

碰巧有两个班,这里有def \方法:RationalMyObject,并有两个隐含的方法太:pointToRationalpointToMyObject对于这两个类。

但是由于RationalMyObject都定义了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 \方法或不删除隐式转换方法之一?

回答

3

你可以这样做:

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 

另一种方式它的移动你的implicits成单独的对象:

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

不是。您有时可能会滥用implicit resolution order(例如,通过将其中一个隐含项移动到伴随对象中,或者将伴随对象扩展的特征,以便仅在您的直接作用域中查找隐含项后才能看到它)。但通常你应该确保只有一个合适的隐含范围。记住,你可以随时创建内部范围与{}并导入一个隐含刚才那一范围:

val result = {import someImplicit; p \ 6} 
+0

小心按照上面的代码给出完整的示例? – null

相关问题