如果我这样做:
object Parent {
class Inner extends Testable { type Self <: Inner }
def inner = new Inner()
}
object Child {
class Inner extends Parent.Inner { type Self <: Inner }
def inner = new Inner()
}
trait Testable {
type Self
def test[T <: Self] = {}
}
object Main {
// this works
val p: Parent.Inner = Child.inner
// this doesn't
val h = Parent.inner
h.test[Child.Inner]
}
我收到此错误:
error: type arguments [Child.Inner] do not conform to method test's type parameter bounds [T <: Main.h.Self]
h.test[Child.Inner]
当我的Self类型为Parent.Inner和Child.Inner&lt;:Parent.Inner?
时,为什么会出现此错误如果我将type Self <: Inner
更改为type Self = Inner
然后更改override type Self = Inner
,我会收到此错误:
overriding type Self in class Inner, which equals Parent.Inner;
type Self has incompatible type
class Inner extends Parent.Inner { override type Self = Inner }
答案 0 :(得分:4)
这是路径相关类型的问题。
对象test
的{{1}}方法不会像您假设的那样,期望h
的子类型。它期望Parent.Inner
的子类型是稍微不同的类型。即使h.Self
是Child.Inner
的子类型,它也不是Parent.Inner
的子类型,这也是编译器抱怨的原因。
类型成员的问题是它们路径依赖 - 它们被绑定到它们的封闭实例,而scalac将不允许你传递另一个实例的类型成员的类型成员实例是预期的。 <{1}}根本不受任何实例约束,也会被拒绝。
为什么需要这个?看看这个非常相似的代码:
h.Self
在查看类型时,此代码与您的代码完全相同(特别是Child.Inner
的类型完全相同)。但是这段代码显然不正确,因为object Main {
class C extends Child.Inner { type Self = C }
val h: Parent.Inner = new C
h.test[Child.Inner]
}
实际上是h
而h.Self
不是C
的子类型。这就是scalac正确拒绝它的原因。
您可能希望在代码段scalac中记住Child.Inner
的类型完全 C
,但不幸的是它并不保留该信息。它只知道h
是Parent.Inner
的某个子类型。
答案 1 :(得分:-1)
您似乎将def inner = new Inner()
视为一个字段,而不是将其视为val
。不同之处在于,在加载类时确定值,而使用def
关键字的值在运行时确定。这可能不是你想要的,因为它回答了另一个问题,但似乎有一些时髦的事情发生在这里。
因为我很好奇自己:
val p : Parent.Inner = Child.inner
这显然是正确的,用这一行:
class Inner extends Parent.Inner
但是,如果我们这样做:
val h = Parent.inner
h.test[Parent.Inner]
无效,但出现以下错误:
type arguments [Parent.Inner] do not conform to method test's type parameter bounds [T <: h.Self] h.test[Parent.Inner]
更奇怪(或者可能并不奇怪,因为这是所有的子类型),这有效:
h.test[Nothing]