2013-06-29 64 views
1

我有一个奇怪的问题,也许是因为我的班结构是一个有点复杂,但无论如何:斯卡拉:泛型和可变的继承问题

所以首先我有两个抽象类: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() 
    } 
} 

然后我就一个对象TestObject2扩展TestAbstract2和基本类的Test2扩展TestAbstract1,并具有实现valTest

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

object TestObject2 extends TestAbstract2[Test2] { } 

的问题在这里:当我编译,它告诉me:

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

[错误]值valTest有不兼容的类型

[错误] VAL valTest:TestAbstract2 [Test2的] = TestObject2

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

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

谢谢!

回答

5

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

Test2 <: TestAbstract1 

这并不是说情况:

TestAbstract2[Test2] <: TestAbstract2[TestAbstract1] 

看一看here如果这没有意义的你。

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

您有以下选择:

  1. 声明TestAbstract2为协变:

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

    val valTest: TestAbstract2[_ <: TestAbstract1] 
    
  3. 参数多态TestAbstract1在TY内TestAbstract2的PE:在

    class Test2 extends TestAbstract1[Test2] 
    

注意,使用F-界多态性的选择(通过本身在TestAbstract1函数边界T):

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

更改Test2到第三个例子在这里有点武断。我只是需要一些类型来为示例起见,并且在您的示例中它可以工作(查看Test2的定义时)。这三个版本中哪一个最适合你取决于你想如何使用这些类。

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

+0

非常感谢你,它的工作就像一个魅力!我将TestAbstract2声明为协变,但事实上,TestAbstract2扩展了其他类型的参数化类(是的,还有一个),并且我必须对此声明使用@uncheckedVariance。但它按预期工作;)再次:谢谢! – Zarkus13

+0

@ Zarkus13很高兴为你效劳。注意使用'@ uncheckedVariance'!它可能允许您以不安全的方式使用方法。 (请参阅我答案中的链接) – gzm0