我有一些麻烦让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
的“基础类型字符串”,但丢失了x
为Bar#X
的信息。如果我注释类型,它可以正常工作:
baz[Bar](x)
有没有办法让Scala推断baz
的正确类型参数?
如果没有,那么一般的答案是什么使它变得不可能?
答案 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。