2012-07-02 34 views
2

我想定义一个方法参数化类型T具有取决于什么隐式参数可以找到Box[T]类型的行为。以下代码将此方法定义为foo。当与foo[Int]foo[String]呼叫时,将按照预期返回1"two"为什么Scala的类型推理失败,这组隐式参数涉及参数化类型?

凡事情变得怪异的是方法栏。它被定义为返回一个Int,而不是foo[Int]我只是foo。我的希望是,编译器会推断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[Int]替换foo编译得很好。更简单的情况下,没有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有效?

回答

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
+0

我之前没有使用上下文边界。我不确定这是否符合我的实际情况,但它肯定是一个值得注意的有趣工具。 – toddaaro

+0

我试图争取上下文边界来获得我想要的行为,但无法做到。我的主要目标是使得'foo'只要能被推断就不需要指定'T'。虽然上下文边界似乎比第二个参数列表更清洁。 – toddaaro

1

这可能与SI-3346类型签名约束,虽然它是隐式转换隐含参数,在这里你有一个隐含的。

+0

感谢您的指针。这看起来似乎可能是相关的,但我必须更多地解决这种情况。 – toddaaro