2012-06-28 57 views
2

更新:我用一個更小更精確的例子來說明我的問題。以下「非法繼承」(Scala 2.9.2)背後的原因是什麼?

假設,我們有如下定義:

class A 
trait TraitForA extends A 

class D[T] 
trait TraitForD extends D[A] 

然後我們可以創建這樣一個對象:

scala> new D[A] with TraitForD 
res0: D[A] with TraitForD = [email protected] 

但是我們不能創建下列對象:

scala> new D[A with TraitForA] with TraitForD 
<console>:12: error: illegal inheritance; 
anonymous class $anon inherits different type instances of class D: 
D[A] and D[A with TraitForA] 
      new D[A with TraitForA] with TraitForD 
       ^

同樣的事情發生時,使用自我類型的性狀而不是extends

scala> trait TraitForD2 { self: D[A] => } 
defined trait TraitForD2 

scala> new D[A with TraitForA] with TraitForD2 
<console>:12: error: illegal inheritance; 
self-type D[A with TraitForA] with TraitForD2 does not conform to TraitForD2's 
selftype TraitForD2 with D[A] 
       new D[A with TraitForA] with TraitForD2 
             ^

上面的創建有什麼(確切)錯誤?

我的猜測是,D[A with TraitForA]未被視爲類型D[A]。當在類D中使用協變註釋+T時,這兩個示例都有效。

請問有人可以解釋爲什麼這些例子失敗,他們爲什麼與+T合作?

獎金問題:有沒有辦法讓示例運行沒有+T

+0

我認爲你的解釋大多是正確的。同樣考慮到類型參數會被擦除,所以你不可能將兩個不同的類型參數混合在一起。我不明白你的最後一句話(其中一部分是它有一個語法問題),也許可以澄清,因爲這最終似乎是你的問題。 –

+0

@Sciss謝謝你的信息。我改述了我的問題。 –

+0

好吧,我會看看。我修正了'性狀TraitForA'的性狀TraitForA延伸A'因爲我認爲這就是你的意思。 –

回答

2

考慮

class C[T]{ def f(t: T): T = t } 

C[A with Y]說,這將有一個f,將只需要A with Y,並且將只返回A with YC[A]不能滿足這個要求的功能。所以兩者有衝突。

由於類型聲明的成功不取決於涉及的任何類的方法的詳細信息,因此Z1 with Z2或任何其他合併方法C[A]C[A with Y]必須是錯誤的。

0

要查看差異問題,讓我們在'TraitForX'中添加一些方法。爲了簡單起見,我將稱這些性狀爲A1D1,並且爲了簡單起見,我還將製作AD特徵。我不知道你怎麼設計出有趣的結構 - 我不知道trait甚至可以延伸class,這是奇怪的,它是允許的!

trait A 
trait A1 extends A { def schoko = 33 } 

trait D[T] { def result: T } 
trait D1 extends D[A] { 
    def result: A = new A {} 
} 

現在我們知道,我們可以做一些事情的A1實例,它是不可能的A一個實例。此外,D1具有result的具體實現。

它仍然是可能重現你的情況:

new D[A] with D1 // works. 

new D[A with A1] { // works. 
    def result = new A with A1 {} 
    def test = result.schoko 
} 

你可以看到,test可以調用方法result和,因爲DA with A1 parametrised(這是一樣的A1的方式),可隨後致電schoko

由此可見,以下不能正常工作:

new D[A with A1] with D1 { 
    def test = result.schoko 
} 

編譯器會說value schoko is not a member of A,這只是意味着它拒絕接受D否則parametrised。 result已在D1中實施以返回A(其不知道schoko)的實例,因此這裏存在固有衝突。


現在,當D改爲

trait D[+T] { def result: T } 

(其餘全部如上仍然),你只是 '推遲' 的問題:

new D[A with A1] with D1 

編譯器現在抱怨error: overriding method result in trait D of type => A with A1 (你認爲這是工作,因爲你實際上沒有實現result)。

因此,方差註釋允許你做某些你以前不能做的事情。如果你還沒有實施result,以下將是完全有可能的:

trait D2 extends D[A] 

new D[A with A1] with D2 { 
    def result = new A with A1 {} 
} 
相關問題