Scala Map将泛型类作为键/值类型

时间:2017-02-23 23:13:01

标签: scala generics shapeless

我试图在scala中实现以下功能,这似乎超出了我的"泛型"技能:

我有2个通用类:

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])

但不是

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) //

我在想像无形的图书馆可以帮忙吗?

2 个答案:

答案 0 :(得分:3)

我认为这会强制执行您之后的限制。

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

asbsaibi的其他组合都不会编译。

答案 1 :(得分:0)

我认为最好的办法是在Scala的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] = 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)
                    ^
相关问题