Scala:泛型和变量继承问题

Zar*_*s13 1 generics inheritance scala scala-2.10

我有一个奇怪的问题,也许是因为我的课程结构有点复杂,但无论如何:

首先,我有2个抽象类:TestAbstract1和TestAbstract2.

  • TestAbstract2采用扩展TestAbstract1的类型
  • TestAbstract1声明一个名为valTest的val ,其类型为TestAbstract2 [TestAbstract1],必须在子类中实现

代码:

abstract class TestAbstract1 {
    val valTest: TestAbstract2[TestAbstract1]

    def meth1(): List[TestAbstract1] = {
        valTest.meth2()
    }
}

abstract class TestAbstract2[T <: TestAbstract1] {
    def meth2(): List[T] = {
        List()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个扩展TestAbstract2的对象TestObject2,以及扩展TestAbstract1的基本类Test2,并且必须实现valTest:

class Test2 extends TestAbstract1 {
    val valTest: TestAbstract2[Test2] = TestObject2
}

object TestObject2 extends TestAbstract2[Test2] { }
Run Code Online (Sandbox Code Playgroud)

问题在于:当我编译时,它告诉我:

[error]覆盖类型为models.test.TestAbstract2 [models.test.TestAbstract1]的类TestAbstract1中的值valTest;

[error] value valTest具有不兼容的类型

[error] val valTest:TestAbstract2 [Test2] = TestObject2

我不知道我做错了什么,因为如果我考虑多态性规则,它应该没问题......

你有什么主意吗 ?或者甚至可能更好地做我想做的事情?

谢谢 !

gzm*_*zm0 5

在您的示例中,TestAbstract2不是协变的.意思是即使我们有

Test2 <: TestAbstract1
Run Code Online (Sandbox Code Playgroud)

事实并非如此:

TestAbstract2[Test2] <: TestAbstract2[TestAbstract1]
Run Code Online (Sandbox Code Playgroud)

如果这对你没有意义,请看看这里.

在您的示例中,valTest声明Test2为类型TestAbstract2[Test2]但预期是TestAbstract2[TestAbstract1],因此错误.

您有以下选择:

  1. 声明TestAbstract2为协变:

    class TestAbstract2[+T <: TestAbstract1]
    
    Run Code Online (Sandbox Code Playgroud)
  2. valTest使用wildchard类型声明:

    val valTest: TestAbstract2[_ <: TestAbstract1]
    
    Run Code Online (Sandbox Code Playgroud)
  3. 参数化TestAbstract1内部的类型TestAbstract2:

    class TestAbstract1[T <: TestAbstract1[T]] {
      val valTest: TestAbstract2[T]
      // ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    更改Test2到:

    class Test2 extends TestAbstract1[Test2]
    
    Run Code Online (Sandbox Code Playgroud)

注意,在第三个例子中使用F-有界多态(在其T自身的函数中的边界TestAbstract1)的选择在某种程度上是任意的.我只是为了示例而需要一些类型,并且在您的示例中它可以工作(当查看定义时Test2).这三个版本中哪一个最适合您取决于您​​希望如何使用这些类.

如果这还不够,请在您的问题中提供更多详细信息,我们将很乐意为您提供帮助.