【问题标题】:Why does Scala's type inferencer fail with this set of implicit arguments involving parameterized types?为什么 Scala 的类型推断器会因这组涉及参数化类型的隐式参数而失败?
【发布时间】:2012-07-02 21:07:31
【问题描述】:

我想定义一个用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"

}

在导致这种行为的这个 sn-p 中发生了什么?隐式参数、类型推断和擦除之间的这种交互会导致问题吗?有没有办法修改此代码以使def foo: Int = bar 行有效?

【问题讨论】:

    标签: scala type-inference implicit type-erasure


    【解决方案1】:

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

    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 的类型签名中使用上下文绑定

    【讨论】:

    • 我之前没有使用过上下文边界。我不确定这是否适用于我的实际情况,但它肯定是一个需要注意的有趣工具。
    • 我尝试调整上下文边界以获得我想要的行为,但无法做到。我的主要目标是使foo 在使用时不需要指定T,只要它可以被推断出来。不过,上下文边界确实比第二个参数列表更清晰。
    【解决方案2】:

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

    【讨论】:

    • 感谢您的指点。这似乎是相关的,但我将不得不对这种情况进行更多的思考。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 2011-03-19
    • 2017-06-22
    • 2018-03-16
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多