2016-10-01 81 views
0

我在Scala中有一個通用的F-bound特徵。讓我編寫方法返回相同的底層實現類型,超!但是現在讓我們說一個子特質定義了需要F-邊界的方法。 Scala是送我回來的編譯錯誤是沒有意義:Scala - 繼承樹中的多個F-bound類型

package sandbox 

import sandbox.ComplexImpl.AnyComplexImpl 

import scala.language.existentials 

trait FBounded[IMPL <: FBounded[IMPL]] { self: IMPL => 
    def foo: IMPL 
} 

trait FBoundedUser[F <: FBounded[F]] { 
    def bar(value: F): F = value.foo 
} 

trait SimpleImpl extends FBounded[SimpleImpl] { 
    override def foo: SimpleImpl = this 
} 

object SimpleUser extends FBoundedUser[SimpleImpl] 

// A-OK so far... 

trait ComplexImpl[IMPL <: ComplexImpl[IMPL]] extends FBounded[IMPL] { self: IMPL => 
    def baz: IMPL 
} 

object ComplexImpl { 
    type AnyComplexImpl = ComplexImpl[T] forSome { type T <: ComplexImpl[T] } 
} 

object ComplexUser1 extends FBoundedUser[ComplexImpl[_]] 
object ComplexUser2 extends FBoundedUser[AnyComplexImpl] 

試圖用任何的ComplexUser1ComplexUser2導致編譯:

Error:(32, 29) type arguments [sandbox.ComplexImpl.AnyComplexImpl] do not conform to trait 
       FBoundedUser's type parameter bounds [F <: sandbox.FBounded[F]] 

這是沒有意義的我。 AnyComplexImpl絕對實現了FBounded。我錯過了什麼,或者是類型檢查器在這裏讓我失望?

編輯:

class Concrete() extends ComplexImpl[Concrete] { 
    override def baz: Concrete = this 

    override def foo: Concrete = this 
} 
object ComplexUser3 extends FBoundedUser[Concrete] 

編譯就好了。那麼爲什麼不能使用通用版本呢?

回答

1

該約束條件要求AnyComplexImpl實施FBounded[AnyComplexImpl],它不是,而不僅僅是FBounded[T] forSome { type T <: ComplexImpl[T] }

它可以工作,如果你使FBoundedComplexImpl covariant。編譯器原因:

  1. AnyComplexImpl是任何ComplexImpl[T],其中T <: ComplexImpl[T]的超類型;

  2. 因此FBounded[T] forSome { type T <: ComplexImpl[T] }FBounded[AnyComplexImpl]的子類型;因此AnyComplexImplFBounded[AnyComplexImpl]的子類型。

但我懷疑試圖混合F-bound類型和existentials可能導致其他問題。 ComplexUser1ComplexUser2不能編譯的原因正是它們不是通用的。請考慮使用實際通用的版本:

def complexUser4[T <: ComplexImpl[T]] = new FBoundedUser[T] {} 
+0

啊哈! Co/contravariance是類型系統的一個角落,我仍然試圖更好地把握。謝謝。 –