我可以告诉scala如何更喜欢更具体的隐含,而不是给出“含糊不清的”错误吗?

时间:2013-11-14 01:59:22

标签: scala scala-2.10 implicits

以下代码给出了错误。

class Base { }
class Sub extends Base { }

class Writer[-T] {
  def write(t: T) { }
}

object AmbImplicits {

  implicit object BaseWriter extends Writer[Base]
  implicit object SubWriter extends Writer[Sub]

  def foo[T](t: T)(implicit ev: Writer[T]) {
    println(s"foo $t $ev")
  }

  def main(args: Array[String]) {
    val base = new Base
    val sub = new Sub
    foo(base)
    foo(sub)
  }

}

错误:

/Workspace/AmbImplicits.scala:24: error: ambiguous implicit values:
both object SubWriter in object AmbImplicits of type AmbImplicits.SubWriter.type
and object BaseWriter in object AmbImplicits of type AmbImplicits.BaseWriter.type
match expected type Writer[Sub]
    foo(sub)
       ^

在我的实际代码中,显式传递隐式参数并不是那么简单。有没有办法告诉它总是更喜欢SubWriter而不是BaseWriter,因为前者更具体?没有像foo(sub)(SubWriter)那样手动传递它?

2 个答案:

答案 0 :(得分:4)

如果由于Base和Sub是Java类型而无法做Shadowlands所建议的,那么你可以通过将它移动到继承链来降低BaseWriter隐含的优先级:

trait LowPriorityImplicits { implicit object BaseWriter extends Writer[Base] }

object AmbImplicits extends LowPriorityImplicits {
  implicit object SubWriter extends Writer[Sub]

  def foo[T](t: T)(implicit ev: Writer[T]) {
    println(s"foo $t $ev")
  }

  def main(args: Array[String]) {
    val base = new Base
    val sub = new Sub
    foo(base)
    foo(sub)
  }
}

答案 1 :(得分:3)

如果你能够,将implicits放在从Base派生的每个类型的伴随对象中,而不是在foo方法的对象中:

class Base { }
object Base { implicit object BaseWriter extends Writer[Base] }
class Sub extends Base { }
object Sub { implicit object SubWriter extends Writer[Sub] }

object NotAmbImplicits {

  def foo[T](t: T)(implicit ev: Writer[T]) {
    println(s"foo $t $ev")
  }

  def main(args: Array[String]) {
    val base = new Base
    val sub = new Sub
    foo(base)
    foo(sub)
  }

}

编译器将在伴随对象中查找传递给T的给定foo以查看它是否可以使用隐式来源。