【问题标题】:Scala : generics and variable inheritance issueScala:泛型和变量继承问题
【发布时间】:2013-06-26 20:43:57
【问题描述】:

我有一个奇怪的问题,可能是因为我的类的结构有点复杂,但无论如何:

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

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

代码:

abstract class TestAbstract1 {
    val valTest: TestAbstract2[TestAbstract1]

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

abstract class TestAbstract2[T <: TestAbstract1] {
    def meth2(): List[T] = {
        List()
    }
}

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

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

object TestObject2 extends TestAbstract2[Test2] { }

问题就在这里:当我编译时,它告诉我:

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

[error] value valTest 的类型不兼容

[错误] val valTest: TestAbstract2[Test2] = TestObject2

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

你有什么想法吗?或者甚至是做我想做的更好的方式?

谢谢!

【问题讨论】:

    标签: scala generics inheritance scala-2.10


    【解决方案1】:

    在您的示例中,TestAbstract2 不是协变的。这意味着即使我们有

    Test2 <: TestAbstract1
    

    事实并非如此:

    TestAbstract2[Test2] <: TestAbstract2[TestAbstract1]
    

    看看here如果这对你没有意义。

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

    您有以下选择:

    1. 将TestAbstract2 声明为协变:

      class TestAbstract2[+T <: TestAbstract1]
      
    2. 使用通配符类型声明valTest:

      val valTest: TestAbstract2[_ <: TestAbstract1]
      
    3. 在内部TestAbstract2的类型上参数化TestAbstract1:

      class TestAbstract1[T <: TestAbstract1[T]] {
        val valTest: TestAbstract2[T]
        // ...
      }
      

      将Test2 更改为:

      class Test2 extends TestAbstract1[Test2]
      

    请注意,在第三个示例中选择使用 F 有界多态性(通过 TestAbstract1 中的自身函数限制 T)在这里有些随意。为了示例,我只需要输入一些类型,并且在您的示例中它可以工作(查看Test2 的定义时)。这三个版本中哪一个最适合您,取决于您希望如何使用这些类。

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

    【讨论】:

    • 非常感谢,它的工作就像一个魅力!我将 TestAbstract2 声明为协变,但实际上,TestAbstract2 扩展了另一个类型的参数化类(是的,还有一个),我不得不对这个声明使用 @uncheckedVariance。但它按预期工作;)再次:谢谢!
    • @Zarkus13 很高兴它为你解决了。小心使用@uncheckedVariance!它可能允许您以非类型安全的方式使用方法。 (请参阅我的答案中的链接)
    猜你喜欢
    • 2023-03-25
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 2011-08-01
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多