2017-02-23 86 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) 
        ^