您正在使用參數化從類定義的一個不同的另一種類型的參數A
方法。這裏是你用改名參數寫的版本:
trait HasBuffer[+A] {
var items = Buffer[A]()
def add[B](item: B) = items += item
def remove[B](item: B) { items -= item }
def set(is: Buffer[A]) { items = is }
def clear { items clear }
}
現在應該清楚,爲什麼編譯器會拒絕這個。
相反,你可以簡單地寫這樣的方法:
def add(item: A) = items += item
def remove(item: A) { items -= item }
但是,你仍然會收到編譯器錯誤指出協變型A
的禁忌和不變的位置出現。
協變的一點是,如果你期望HasBuffer[AnyVal]
可以通過HasBuffer[Int]
。但是,如果您希望AnyVal
,並使用該類型的add
方法爲好,你就可以到一個完全不同類型添加到您的HasBuffer[Int]
。因此,編譯器拒絕這個。
相反,你必須提供一個下界類型參數是這樣的:
trait HasBuffer[+A, V <: A] {
var items = Buffer[V]()
def add(item: V) = items += item
def remove(item: V) { items -= item }
def set(is: Buffer[V]) { items = is }
def clear { items clear }
}
有了這個,你現在可以有一個像下面的方法:
def doSomething[X <: AnyVal](b : HasBuffer[AnyVal, X], e : X) = b.add(e)
這種方法將工作在各種滿足所需下限的HasBuffer
類型參數組合上。
精神上比較這與沒有提供一個下界的想法。然後,該方法會成爲這樣的事情:
// doesn't make much sense!
def doSomething(b : HasBuffer[AnyVal], e : AnyVal) = b.add(e)
如果調用此方法HasBuffer[Int]
類型的對象和Double
這將是所有快樂。你可能會不高興lateron不過,當你發現你的緩衝區應該只包含Int
小號現在包含一個Double
。
是的,我不得不承認這個解釋是非常詳細的,因此是一個可能遇到類似麻煩的人的方向。至於Scala編譯器 - 太糟糕了,它確實允許這種等價命名的類型參數。完全禁止它們是合乎邏輯的。由於沒有人願意將他的類型參數命名爲類似這樣的類型參數以及那些想要這樣做的類型參數,因此只會聲明不好的樣式編碼。代碼混淆是一個側面,它不應該出現在純編程中。 – noncom 2012-02-03 13:42:35