Scala 隐式转换在某些条件下应用,但在其他条件下不应用

标签 scala implicit-conversion implicit compiler-bug implicits

这是一个简单的复制器,我在其中定义了一个带有隐式重新排序转换的“可交换”对类型。如果函数的参数f,编译器会按预期应用隐式转换。位于预先存在的命名值中(示例中为 t)。但是,如果我尝试调用 f直接在字面上 CommutativePair ,它会因类型错误而失败。在这种情况下,编译器不会应用隐式重新排序转换。

object repro {
  import scala.language.implicitConversions

  case class CommutativePair[A, B](a: A, b: B)

  object CommutativePair {
    // Support a kind of commutative behavior via an implicit reordering
    implicit def reorderPair[B, A](pair: CommutativePair[B, A]) =
      CommutativePair(pair.b, pair.a)
  }

  // The idea is to allow a call to 'f' with Pair[Int, String] as well,
  // via implicit reorder.
  def f(p: CommutativePair[String, Int]) = p.toString

  val t = CommutativePair(3, "c")

  // This works: the implicit reordering is applied
  val r1 = f(t)

  // This fails to compile: the implicit reordering is ignored by the compiler
  val r2 = f(CommutativePair(3, "c"))
}

最佳答案

我相信它正在达到 scala 推理的极限,这是由它搜索解决方案的顺序触发的。在第一种情况下:

val t = CommutativePair(3, "c")

推断已将类型锁定为 CommutativePair[Int,String] ,因为它是唯一可以根据参数工作的。所以当它调用时:
val r1 = f(t)

它在 Commutative[Int,String] 上得到类型不匹配=!= Commutative[String,Int] ,然后它搜索implicits并找到上面的那个。

在第二种情况下,scala 试图找出类型,从外部进入:
val r2 = f(CommutativePair(3, "c"))
  • 首先,它确定f , 必带Commutative[String,Int] .
  • 那么,CommutativePair(...,...)必须是 Commutative[String,Int] (因为,它还没有从它的参数中找出它的类型)。
  • 现在它查看 CommutativePair(...) 的参数并发现它们是错误的类型。但这不会触发隐式转换,因为它认为不匹配存在于参数中,而不是整体上CommutativePair(...) .

  • 实际上,锁定类型参数(通过显式传递它们或首先绑定(bind)到 val)修复了错误。

    关于Scala 隐式转换在某些条件下应用,但在其他条件下不应用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32211381/

    相关文章:

    scala - 有没有办法让ArrowAssoc在模式匹配中工作?

    scala - 为什么每次从命令提示符启动 Scala sbt 时都会更新?

    scala - Scala 2.9 中定义的 Numeric 和 Double 之间的隐式转换在哪里

    scala - 将scala.math.Integral传递为隐式参数

    Scala:从特征实例化时使用 def 还是 val?

    scala - 在 scala 中读取 csv 的通用类

    sql - 奇怪的选择结果

    c# - 为什么 C# 允许从 Long 到 Float 的*隐式*转换,而这可能会丢失精度?

    c# - 我如何隐式地将我的类转换为另一种类型?

    generics - Scala 泛型和数字隐式