7

这是一个简单的复制器,我在其中定义了一个带有隐式重新排序转换的“可交换”对类型。f如果函数的参数在预先存在的命名值中(t在示例中),则编译器将按预期应用隐式转换。但是,如果我尝试f直接调用 literal 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"))
}
4

1 回答 1

2

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

val t = CommutativePair(3, "c")

推理已将类型锁定为CommutativePair[Int,String],因为它是唯一可以基于参数工作的类型。所以当它调用时:

val r1 = f(t)

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

在第二种情况下,scala 试图找出类型,从外部进入:

val r2 = f(CommutativePair(3, "c"))
  • 首先,它决定了f,必须采取Commutative[String,Int]
  • 然后,它CommutativePair(...,...) 必须Commutative[String,Int](因为它还没有从它的参数中找出它的类型)。
  • 现在它查看参数CommutativePair(...)并发现它们是错误的类型。但这不会触发隐式转换,因为它认为不匹配存在于参数中,而不是整体上CommutativePair(...)

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

于 2015-11-03T22:36:52.807 回答