【问题标题】:Can I tell scala how to prefer more specific implicit, rather than give "ambiguous implicit" error?我可以告诉 scala 如何更喜欢更具体的隐式,而不是给出“模棱两可的隐式”错误吗?
【发布时间】:2013-11-26 21:36:29
【问题描述】:

以下代码给出错误。

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) 那样手动传递它?

【问题讨论】:

    标签: scala scala-2.10 implicits


    【解决方案1】:

    如果由于 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)
      }
    }
    

    【讨论】:

      【解决方案2】:

      如果可以的话,将隐式放入从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)
        }
      
      }
      

      编译器将在伴生对象中查找传递给foo 的给定T,看看它是否可以从那里使用隐式。

      【讨论】:

      • 实际上 Base 和 Sub 类型是在 Java 中定义的。但我也许可以移植它们。无论哪种方式,这都是有帮助的,如果我不学习另一种方式,我会立即将其标记为答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      • 1970-01-01
      相关资源
      最近更新 更多