你还可以:
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 <:富告诉那个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没有区别的字符串。
不是一个答案,但值得注意的是,如果您使用类型指示符而不是类型投影来键入'x',它将起作用 - 例如, '对象BAR扩展Bar; val x:BAR.X =“a”;巴兹(X)'。 –
另外值得注意的是,你可以说服编译器,你真的想把'x'作为或多或少的像'Bar#X'那样令人难以置信的'val x:bX forSome {val b:Bar} =“ a“:bX forSome {val b:Bar}'。 –
似乎很奇怪的用例。你为什么想这样做? –