簡體   English   中英

在Scala中綁定現有類型

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM