[英]Binding Existential types in Scala
这是我的基本CMap,它将类(任何T的Class [T])映射到任何类型的值。
scala> type CMap = Map[Class[T] forSome{type T}, Any]
defined type alias CMap
scala> val cMap: CMap = Map(classOf[Int]->5, classOf[String]->"abc", classOf[Double]->"ddd")
cMap: CMap = Map(int -> 5, class java.lang.String -> abc, double -> ddd)
现在,我需要一个“绑定的” CMap(称为CMapBind)。 像CMap一样,它将类(任何类)映射到值(任何值)。 但是与CMap不同,CMapBind在键和值之间具有类型绑定,这意味着我希望以下行为:
val cMapBind: CMapBind = Map(classOf[Int]->5, classOf[String]-> "aa") // should compile
val cMapBind: CMapBind = Map(classOf[Int]->5, classOf[String]-> 0) // should fail compile
如何实现CMapBind?
我知道以下两个在语法/逻辑上不会起作用。
scala> type CMapBind = Map[Class[T] forSome{type T}, T]
<console>:8: error: not found: type T
type CMapBind = Map[Class[T] forSome{type T}, T]
scala> type CMapBind = Map[Class[T], T] forSome{type T}
scala> val cMapBind: CMapBind = Map(classOf[Int]->5, classOf[String]->"str")
<console>:8: error: type mismatch;
found : scala.collection.immutable.Map[Class[_ >: String with Int],Any]
required: CMapBind
(which expands to) Map[Class[T],T] forSome { type T }
val cMapBind: CMapBind = Map(classOf[Int]->5, classOf[String]->"str")
请注意,这里我以类型构造函数Class [T]为例说明问题。 在我的代码中,我有自己的类型,例如trait Animal[S, T], class Dog extends Animal[Int, String]
。
编辑1:我应该提到我以不可变Map为例,但是我真正需要的是可变的异构Map)。
让我们尝试实现可变的HMap
。 @MilesSabin在这里提供了有关Scala类型系统的一些解释: http : //www.chuusai.com/2011/07/16/fundeps-in-scala/
这个想法是要静态检查构造函数(在这里您将看到,它的灵巧性取决于您的双手,因此可以生成它或其他东西)和insert方法。 顺便说一句,不变HMap
以无形方式实现。
import scala.collection.mutable.Map
class HMapBuilder[R[_, _]] { // constructor arity is two
def apply[K1, V1](e1: (K1, V1))(implicit ev1: R[K1, V1]) =
new HMap[R](Map(e1))
def apply[K1, V1, K2, V2](e1: (K1, V1), e2: (K2, V2))
(implicit ev1: R[K1, V1], ev2: R[K2, V2]) =
new HMap[R](Map(e1, e2))
}
因此,它是地图的构造函数。 证据将静态检查插入数据的类型。 接下来,包装默认的scala集合:
class HMap[R[_, _]](underlying : Map[Any, Any] = Map.empty) {
def get[K, V](k : K)(implicit ev : R[K, V]) : Option[V] =
underlying.get(k).asInstanceOf[Option[V]]
def +=[K, V](kv : (K, V))(implicit ev : R[K, V]) : HMap[R] = {
underlying += kv
this
}
def -=[K](k : K) : HMap[R] = {
underlying -= k
this
}
override def toString = underlying.toString
}
最后包装HMapBuilder
,使它成为一个令人愉快的构造函数:
object HMap {
def apply[R[_, _]] = new HMapBuilder[R]
def empty[R[_, _]] = new HMap[R]
def empty[R[_, _]](underlying : Map[Any, Any]) =
new HMap[R](underlying)
}
结果,用法类似于shapeless
HMap
:
class Mapping[K, V]
implicit def mappingFromClass[A] = new Mapping[Class[A], A]
val hm = HMap[Mapping](classOf[Int] -> 5) // ok
hm += (classOf[String] -> "string") // ok
hm += (classOf[Boolean] -> false) // ok
hm += (classOf[Double] -> "sss") // compile fail
可以正常工作。 我只实现了插入和删除功能,其他功能也可以用相同的方式定义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.