2017-03-17 55 views
3

所以這裏是我用Scala時遇到的各種情況的問題 - 即使情況很明顯,它似乎也忽略了隱含類型。誠然,這可能是我承認我的理解,但是當涉及到強調佔位符時,我仍然遇到麻煩。例如下面(這是虛構的,只是爲了證明這一點)。特徵X的第二個位置必須是<:X某些種類的X [,]。這裏沒有什麼不明確的地方 - 所以scala看到這個位置的任何地方,不管它編碼多麼微弱 - 接觸點是X,我應該可以訪問像「doX」這樣的函數。這不是無可爭議的嗎?無論我在代碼中如何處理這個位置,我都必須至少得到X.當你深入到類型系統時,爲什麼Scala會不斷忽略這個事實?任何指針將不勝感激,謝謝!爲什麼Scala有時會忽略明確定義的類型?

object TestRun extends App { 

    trait X[T, Y<:X[_,_]] { 
    def doesX:Unit 
    def providesY:Y 
    } 

    class Test extends X[Int,Test]{ 
    override def doesX: Unit = println("etc..") 
    def providesY:Test = new Test 
    } 

    val a:X[_,_] = new Test //yes I know I could define a better here, its just to demo. I shouldn't have to explicitly relabel the 2nd _ as _<:X[_,<:X[ etc.. 
    val b = a.providesY //clearly this has to be at least a (something) WITH X, but scala claims this as "Any" 

    b.doesX //error won't compile!! 

    //trait 

} 

回答

7

當你寫:

val a: X[_, _] = new Test 
      ^
     // This is treated as if the type parameter is Any, for the most part 

你告訴編譯器aX,在那裏你不在乎什麼它的類型參數。也就是說,無界通配符_被假定爲具有Any的上限,就是這樣。

providesY使用的X第二類參數來確定它的返回類型,但對於a編譯器被告知要放棄它。所以b只是一個Any。這是比較容易看到使用REPL:

scala> val a: X[_, _] = new Test 
a: X[_, _] = [email protected] 

scala> val b = a.providesY 
b: Any = [email protected] 

因此,b.doesX無法編譯,因爲編譯器現在認爲它是Any。簡單的解決方案不是爲類型使用通配符(或者一般來說任何存在類型,大多數時候你不需要這些)。

scala> val a: X[Int, Test] = new Test 
a: X[Int,Test] = [email protected] 

scala> val b = a.providesY 
b: Test = [email protected] 

scala> b.doesX 
etc.. 

或者你可以簡單地忽略類型註釋,並讓編譯器推斷出正確的類型。