2011-08-17 78 views
6

我想從Scala的不可變Map導出。它被定義爲這樣的:是否有可能改變Scala中基類/特徵的方差?

trait Map[A, +B] 

不幸的是,我的實現需要是不變的B.我嘗試以下,但沒有成功:

def +(kv : (A, B)) : MyMap[A, B] = { ... } 

override def +[B1 >: B](kv : (A, B1)) : MyMap[A, B1] = 
    throw new IllegalArgumentException() 

也許有與@uncheckedVariance一招?

+1

也許你可以使用會員地圖,而不是派生? – Owen

+0

另外,爲什麼它需要是不變的?我認爲(我不太瞭解斯卡拉),唯一需要不變的時候就是它既可以是源代碼也可以是接收器,但是映射是不可變的,因此它不可能是一個匯。 – Owen

+0

我想實現一個雙向地圖。如果我實現Map,並沒有什麼大不了的,只是委託給定義前向和後向映射的兩個內部映射,但在這種情況下我需要不變。 –

回答

1

完全擺脫協變將當然是不健全的,是不允許的。 鑑於m: Map[A, String]v : Any,你可以做val mm : Map[A, Any] = m + v。這就是Map定義所說的,所有的實現者都必須遵循。你的類可能是不變的,但它必須實現Map的完整協變接口。

現在重新定義+拋出一個錯誤是一個不同的故事(不是很健全)。您的新+方法的問題是,在刪除泛型之後,它的簽名與其他+方法相同。有一個技巧:添加隱式參數,以便在簽名中有兩個參數,這使得它與第一個參數不同。

def +(kv : (A,B))(implicit useless: A <:< A) : MyMap[A,B] 

(它並不真正的問題是什麼隱含的你正在尋找,只要找到一個參數implicit useless: Ordering[String]。作品一樣好)

這樣做,你有超載平時的問題。如果在編譯器不知道的情況下添加B,則會調用失敗的方法。在那裏執行類型檢查可能會更好,這樣B實例就可以被接受。這需要在你的地圖中獲得一個Manifest [B]。

3

麻煩的是,如果你從一個不可變的地圖派生出一個不變的版本,你就會破壞類型安全。例如:

val dm = DiotMap(1 -> "abc") 
val m: Map[Int, Any] = dm 

此聲明有效,因爲Map是協變的。如果您的收藏無法處理協變,那麼當我使用m時會發生什麼?

相關問題