以下代码:
trait Foo {
type T
val x: T
}
trait Bar {
type F <: Foo { type T <: F }
}
class C[B <: Bar](val f: B#F) {
val x: f.T = f.x
}
Scala编译器(2.11.5)拒绝,并显示以下错误消息:
error: type mismatch;
found : C.this.f.x.type (with underlying type C.this.f.T)
required: this.T
val x: f.T = f.x
^
如果省略显式类型声明,则根据typer阶段的输出正确推断类型:
private[this] val x: C.this.f.T = C.this.f.x;
<stable> <accessor> def x: C.this.f.T = C.this.x
如果F
中的Bar
内的Bar
更改为不属于type F <: Foo { type T <: Foo }
成员的类型,即
{{1}}
正常工作。
这是一个错误吗?或者我的一些根本误解?还是一些神秘的功能?
答案 0 :(得分:2)
不是一个明确的答案,而是一些观察......
让我们先看看它有什么作用:
class C[B <: Foo](val f: B) {
val x: f.T = f.x
}
因此编译器在使用值f
的类型投影时会丢失。如果您“修复”该投影,它似乎也有效:
class D[B <: Bar](val f: B#F) {
val g: Foo = f
val x: g.T = g.x
}
我一直在与F-bounded类型斗争,直到我让它们“防水”。类型参数与类型成员之间存在一些使前者工作的东西。例如:
trait FooRec[F <: FooRec[F]] extends Foo {
type T = F
}
class E[F <: FooRec[F]](val f: F) {
val x: f.T = f.x
}
最后,您还可以通过将其作为类型参数传入来修复Bar
的类型成员:
class G[F1 <: Foo { type T = F1 }, B <: Bar { type F = F1 }](val f: B#F) {
val x: f.T = f.x
}
类似地,如果你修改了Bar
定义中已有的类型,它就可以了:
trait Baz {
type F <: Foo { type T = F } // stable recursion
}
class H[B <: Baz](val f: B#F) {
val x: f.T = f.x
}
因此,在您的原始定义和应用程序中,上限似乎不够。可能你可以证明编译器对它的拒绝是正确的,但我不知道如何......