对象内类中的 Scala 抽象类型 [英] Scala abstract types in classes within objects

查看:21
本文介绍了对象内类中的 Scala 抽象类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我这样做:

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 时为什么会出现此错误?

Why does this error when I my Self type is Parent.Inner and Child.Inner <: Parent.Inner?

如果我将 type Self <: Inner 更改为 type Self = Inner 然后 override type Self = Inner,我会得到这个错误:

And if I change type Self <: Inner to type Self = Inner and then override type Self = Inner, I get this error:

overriding type Self in class Inner, which equals Parent.Inner;
 type Self has incompatible type
    class Inner extends Parent.Inner { override type Self = Inner }

推荐答案

这是路径依赖类型的问题.

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

The test method of object h does not expect, as you would assume, a subtype of Parent.Inner. It expects a subtype of h.Self which is a slightly different type. Even though Child.Inner is a subtype of Parent.Inner, it is not a subtype of h.Self and that's why the compiler complains.

类型成员的问题在于它们是路径相关的 - 它们绑定到它们的封闭实例并且scalac不允许您传递一个实例的类型成员,而另一个实例的类型成员是预期的.Child.Inner 根本没有绑定到任何实例,也会被拒绝.

The problem with type members is that they are path dependent - they're bound to their enclosing instance and scalac will not allow you to pass type member of one instance where type member of another instance is expected. Child.Inner is not bound to any instance at all and will also be rejected.

为什么需要这个?看看这个非常相似的代码:

Why is this needed? Look at this very similar code:

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 正确拒绝它的原因.

When looking at types, this code is exactly the same as yours (in particular, the type of h is exactly the same). But this code is clearly incorrect, because h.Self is actually C and Child.Inner is not a subtype of C. That's why scalac correctly rejects it.

您可能希望在您的代码片段中,scalac 应该记住 h 的类型是 exactly Parent.Inner,但不幸的是它没有不要保留该信息.它只知道 hParent.Inner 的某个子类型.

You would expect that in your snippet scalac should remember that the type of h is exactly Parent.Inner, but unfortunately it doesn't keep that information. It only knows that h is some subtype of Parent.Inner.

这篇关于对象内类中的 Scala 抽象类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆