如何从投影类型推断出正确的类型参数?

时间:2013-02-06 03:45:08

标签: scala polymorphism type-inference type-projection

我有一些麻烦让Scala从类型投影中推断出正确的类型。

请考虑以下事项:

trait Foo {
  type X
}

trait Bar extends Foo {
  type X = String
}

def baz[F <: Foo](x: F#X): Unit = ???

然后以下编译好:

val x: Foo#X = ???    
baz(x)

但以下内容无法编译:

val x: Bar#X = ???    
baz(x)

Scala看到x的“基础类型字符串”,但丢失了xBar#X的信息。如果我注释类型,它可以正常工作:

baz[Bar](x)

有没有办法让Scala推断baz的正确类型参数?
如果没有,那么一般的答案是什么使它变得不可能?

2 个答案:

答案 0 :(得分:2)

程序通过在上下文中添加此隐式转换进行编译:

implicit def f(x: Bar#X): Foo#X = x

由于这种隐式转换对于任何F <: Foo都是正确的,我想知道为什么编译器本身不会这样做。

答案 1 :(得分:1)

你也可以:

trait Foo {
    type X
}
trait Bar extends Foo {
    type X = String
}
class BarImpl extends Bar{
  def getX:X="hi"
}
def baz[F <: Foo, T <: F#X](clz:F, x: T): Unit = { println("baz worked!")}
val bi = new BarImpl
val x: Bar#X = bi.getX
baz(bi,x)

但:

def baz2[F <: Foo, T <: F#X](x: T): Unit = { println("baz2 failed!")}
baz2(x)

失败了:

test.scala:22: error: inferred type arguments [Nothing,java.lang.String] do not conform to method baz2's type parameter bounds [F <: this.Foo,T <: F#X]
baz2(x)
^
one error found

我认为基本上,F&lt;:Foo告诉编译器F必须是Foo的子类型,但是当它得到X时它不知道你的特定 X来自哪个类。您的X只是一个字符串,并且不会保留指向Bar的信息。

请注意:

def baz3[F<: Foo](x : F#X) = {println("baz3 worked!")}
baz3[Bar]("hi")

也有效。事实上你定义了一个val x:Bar#X = ???只是意味着???被限制为Bar#X可能碰巧在编译时......编译器知道Bar#X是String,因此x的类型只是一个与任何其他String没有区别的String。