2017-02-23 84 views
2

我試圖實現階以下,這似乎是超出了我的「通用」技能:斯卡拉地圖與泛型類以鍵/值類型

我有2個泛型類:

class A[T] 
class B[T] 

我要地圖有的一些BS:

val m = Map[A, B] 

現在,這並不編譯,因爲A和B是通用的,所以

val m = Map[A[_], B[_]] 

我希望能夠存儲任意類型T的A/B對。但是我只想添加通用類型與鍵和值相同的對。所以我可以做

m updated(new A[String], new B[String]) 

但不

m updated(new A[String], new B[Int]) 

我 希望編譯器意識到這一點,所以我可以做

val a = new A[String] 
val b = new A[String] 
val m = Map(a -> b) 
val b: B[String] = m(a) // 

我在想一個圖書館像無形的可能幫幫我 ?

回答

3

我認爲這會強制執行您的限制條件。的asbi

class A[T] 
class B[T] 
val as = new A[String] 
val bs = new B[String] 
val ai = new A[Int] 
val bi = new B[Int] 
val ms: Map[A[X], B[X]] forSome {type X}= Map(as -> bs) // OK 
val mi: Map[A[X], B[X]] forSome {type X}= Map(ai -> bi) // OK 

沒有其他組合bsai,並將彙編。

0

我認爲你最好的選擇是圍繞斯卡拉的Map寫一個包裝。

我很小的實現:

class MyMap[K[_],+V[_]] private(map: Map[Any,Any]) { 
    def apply[T](key: K[T]): V[T] = map(key).asInstanceOf[V[T]] 
    def updated[T1,T2,V1[X] >: V[X]](key: K[T1], value: V1[T2])(implicit ev: T1 =:= T2) = new MyMap[K,V1](map.updated(key,value)) 
} 

object MyMap { 
    def apply[K[_],V[_]] = new MyMap[K,V](Map.empty) 
} 

我使用的是鑄鐵內部,但因爲你請確保進入MyMap的鍵值對始終具有相同類型的參數,應該是非常安全的。

scala> val (ai,as,bi,bs) = (new A[Int], new A[String], new B[Int], new B[String]) 
ai: A[Int] = [email protected] 
as: A[String] = [email protected] 
bi: B[Int] = [email protected] 
bs: B[String] = [email protected] 

scala> var m = MyMap[A,B] 
m: MyMap[A,B] = [email protected] 

scala> m = m.updated(as,bs) 
m: MyMap[A,B] = [email protected] 

scala> m = m.updated(ai,bi) 
m: MyMap[A,B] = [email protected] 

scala> m(as) 
res0: B[String] = [email protected] 

scala> m(ai) 
res1: B[Int] = [email protected] 

無需混合:

scala> m = m.updated(ai,bs) 
<console>:23: error: Cannot prove that Int =:= String. 
     m = m.updated(ai,bs) 
        ^