将泛型类作为键/值类型的Scala映射

将泛型类作为键/值类型的Scala映射,scala,generics,shapeless,Scala,Generics,Shapeless,我试图在scala中实现以下目标,这似乎超出了我的“通用”技能: 我有两个通用类: class A[T] class B[T] 我想把一些As映射到一些Bs: val m = Map[A, B] 因为A和B是泛型的,所以不能编译,所以 val m = Map[A[_], B[_]] 我希望能够为任意类型T存储A/B对。但是,我只希望为键和值添加泛型类型相同的对。所以我能做到 m updated(new A[String], new B[String]) val a = new A[Str

我试图在scala中实现以下目标,这似乎超出了我的“通用”技能:

我有两个通用类:

class A[T]
class B[T]
我想把一些As映射到一些Bs:

val m = Map[A, B]
因为A和B是泛型的,所以不能编译,所以

val m = Map[A[_], B[_]]
我希望能够为任意类型T存储A/B对。但是,我只希望为键和值添加泛型类型相同的对。所以我能做到

m updated(new A[String], new B[String])
val a = new A[String]
val b = new A[String]
val m = Map(a -> b)
val b: B[String] = m(a) //
但不是

m updated(new A[String], new B[Int])
而我 希望编译器知道这一点,这样我就可以

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

我在想像Shapess这样的库可能会有所帮助?

我认为这会加强您所追求的限制

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

as
bs
ai
bi
的其他组合将无法编译。

我认为最好的办法是围绕Scala的
地图编写一个包装

我的最小实现:

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] = A@51084ab3
as: A[String] = A@24b77bb0
bi: B[Int] = B@5b109ef8
bs: B[String] = B@51390faa

scala> var m = MyMap[A,B]
m: MyMap[A,B] = MyMap@666ecbca

scala> m = m.updated(as,bs)
m: MyMap[A,B] = MyMap@23ebc8c8

scala> m = m.updated(ai,bi)
m: MyMap[A,B] = MyMap@1e3e5527

scala> m(as)
res0: B[String] = B@51390faa

scala> m(ai)
res1: B[Int] = B@5b109ef8
禁止混合:

scala> m = m.updated(ai,bs)
<console>:23: error: Cannot prove that Int =:= String.
       m = m.updated(ai,bs)
                    ^
scala>m=m.updated(ai、bs)
:23:错误:无法证明Int=:=字符串。
m=m.更新(ai、bs)
^