2017-03-16 255 views
0

我具有以下特徵:類型參數的類型不匹配

sealed trait Tree[+A] 
case class Leaf[A](value: A) extends Tree[A] 
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A] 

然後我定義一個變量與Branch類型:上述

val t = Branch(Branch(Leaf("S"), Leaf(2)), Leaf(99)) 

代碼工作正常。但是,當我將其更改爲:

val t = Branch[Int](Branch(Leaf("S"), Leaf(2)), Leaf(99)) 

編譯器會抱怨:

Error:(41, 37) type mismatch; 
found : String("S") 
required: Int 
    val t = Branch[Int](Branch(Leaf("S"), Leaf(2)), Leaf(99)) 

當我確定第一Branch類型(在這種情況下爲int),那麼節點將固有的家長嗎?

回答

4

這裏發生的是,在Branch(Leaf("S"), Leaf(2))的情況下,編譯器將嘗試找到一個通用類型。在IntString的情況下,它們的超類型將是Any

問題在於,您正在使用Branch[Int]強制使用分支定義中的類型,該分類被包含的Branch[Any]無效。刪除[Int]將修復編譯錯誤,但最終會得到Branch[Any]

讓我們來細數了一下你的定義:

sealed trait Tree[+A] 

+在這裏說,類型A可協變。我不會詳細介紹差異,因爲有很多很好的文章解釋它(例如here)。基本上這意味着如果StringAny的子類型,那麼Tree[String]將是Tree[Any]的子類型。

case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A] 

我們首先注意到A如何出現在左側樹和右側樹中。那麼當我們把兩棵不同類型的樹放在同一個分支中時會發生什麼呢?

val left = Leaf(1) // Tree[Int] 
val right = Leaf("a") // Tree[String] 
val tree = Branch(left, right) // Tree[???] 

由於A必須在leftright值相同(這就是我們如何定義它),編譯器試圖解決這個問題。所以它問自己:IntString的第一種常見類型是什麼?

 Any 
     ^
    /\ 
    / \ 
    / \ 
AnyVal  AnyRef 
/  \ 
    Int  String 
    \  /
     ... 

這是Scala中的類型層次結構相當簡化。這是更好地說明here。因此,StringInt的常見超類型是Any,這就是爲什麼您的樹將是Tree[Any]

+0

因此,當我不強制使用適當的類型時,任何類型的'Any'都會被使用。 –

+0

不,第一種常見的類型將被使用。在這種情況下,它是「任何」。 –

+0

當我強制類型是一個'Int',那麼所有類型的節點和葉子將是'Int'?它會從分支固有嗎? –