【问题标题】:Scala abstract types in classes within objects对象内类中的 Scala 抽象类型
【发布时间】:2014-07-28 19:17:21
【问题描述】:

如果我这样做:

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 <: parent.inner>


如果我将type Self &lt;: 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 }

【问题讨论】:

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


    【解决方案1】:

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

    对象htest 方法并不像您所假设的那样期望Parent.Inner 的子类型。它需要h.Self 的子类型,这是一个稍微不同的类型。尽管Child.InnerParent.Inner 的子类型,但它不是h.Self 的子类型,这就是编译器抱怨的原因。

    类型成员的问题在于它们是路径相关的 - 它们被绑定到它们的封闭实例并且scalac不允许您传递一个实例的类型成员,而另一个实例的类型成员是预期的。 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 实际上是CChild.Inner 不是C 的子类型。这就是 scalac 正确拒绝它的原因。

    您会期望在您的 sn-p scalac 中应该记住 h 的类型完全正确 Parent.Inner,但不幸的是它没有保留该信息。它只知道hParent.Inner 的某个子类型。

    【讨论】:

    • 嗯,对第一部分是,对第二部分没有。第二件事,关于与动态类型不同的静态类型,正是我想要击败的。关键是要“静态地”检查对象的动态类型(因为没有更好的词)。
    • 你能想出解决路径依赖类型问题的方法吗?
    【解决方案2】:

    您似乎将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]

    更奇怪的是(或者可能不奇怪,因为这是 everything 的一个子类型),它的工作原理是: h.test[Nothing]

    【讨论】:

    • -1:这是类型错误,与加载某些值时无关。
    • 是的,我希望它成为一家工厂。这不是我的实际代码,只是导致问题的代码的隔离。
    猜你喜欢
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    相关资源
    最近更新 更多