Scala抽象类型在对象中的类中

时间:2014-07-28 19:17:22

标签: scala inheritance polymorphism inner-classes abstract-type

如果我这样做:

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 }

2 个答案:

答案 0 :(得分:4)

这是路径相关类型的问题。

对象test的{​​{1}}方法不会像您假设的那样,期望h的子类型。它期望Parent.Inner的子类型是稍微不同的类型。即使h.SelfChild.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] } 实际上是hh.Self不是C的子类型。这就是scalac正确拒绝它的原因。

您可能希望在代码段scalac中记住Child.Inner的类型完全 C,但不幸的是它并不保留该信息。它只知道hParent.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]