为什么 Scala 的类型推断器在涉及参数化类型的这组隐式参数中失败?



我想定义一个用类型 T 参数化的方法,该方法的行为取决于可以找到类型 Box[T] 的隐式参数。以下代码将此方法定义为 foo 。当使用 foo[Int]foo[String] 调用时,它将毫无问题地按预期返回1"two"

事情变得奇怪的是方法栏。它被定义为返回一个Int,但我只是foo,而不是foo[Int]。我希望编译器能够推断T一定是 Int 型。它不会这样做,而是失败:

bash $ scalac Code.scala 
Types.scala:15: error: ambiguous implicit values:
 both value one in object Main of type => Main.Box[Int]
 and value two in object Main of type => Main.Box[java.lang.String]
 match expected type Main.Box[T]
 def bar: Int = foo
             ^
one error found

导致此错误的原因是什么?将foo替换为foo[Int]编译就可以了。没有Box[T]类型的简单情况也可以很好地编译。该示例也在下面,并使用arglebargle而不是 foobar

object Main extends Application {
  case class Box[T](value: T)
  implicit val one = Box(1)
  implicit val two = Box("two")
  def foo[T](implicit x: Box[T]): T = {
    x.value
  }
  // does not compile:
  // def bar: Int = foo
  // does compile
  def bar: Int = foo[Int]
  println(bar)
  // prints 1
  // the simpler situation where there is no Box type
  implicit val three = 3
  implicit val four = "four"
  def argle[T](implicit x: T): T = x
  def bargle: String = argle
  println(bargle)
  // prints "four"
}

代码段中发生了什么导致此行为?隐式参数、类型推断和擦除的这种交互会导致问题吗?有没有办法修改此代码以使行def foo: Int = bar正常工作?

其他人将不得不解释为什么类型推断机制无法处理这种情况,但是如果您希望清理代码,则可以这样做:

object Test extends App {
  case class Box[T](value: T)
  implicit val one: Box[Int] = Box(1)
  implicit val two: Box[String] = Box("two")
  def foo[T : Box]: T = implicitly[Box[T]].value  
  val bar = foo[Int]  
}

请注意:

  1. 我从bar中删除了类型注释,所以你实际上只是指示一次类型(只是在与你想要的不同的地方)
  2. 我使用的是App而不是已弃用的Application
  3. foo 的类型签名中使用上下文绑定

这可能与 SI-3346 有关,尽管那里有隐式转换的隐式参数,这里只有一个隐式参数。

最新更新