在 Scala 的 Map 上键入级别插入和检索特定值

Type level insert and retrieve a certain value on a Map in Scala

给定一个(操作类似的数据结构)Map。是否有类型级别的插入方式?即:

val myMap: Map[Int, String] = Map(1 -> "a", 2 -> "b")
val x: Int = 5
val y: Int = 99

val myMap2 = myMap + (x -> "e")

我希望的是 myMap2 将有某种类型,我可以在其中安全地执行类似 myMap2.retrieve(x) 的操作并编译它和 return "e"。但是 myMap2.retrieve(y) 甚至不应该编译。

每次使用 myMap2.get(y) 时,如果 y 是 Int,您将得到一个 Option 的字符串。 如果您尝试使用任何其他类型,您将遇到编译异常。 例如:myMap2.get("y") 将引发类型不匹配。 所以如果key类型不对就无法编译。

如果您的密钥有不同的类型,Shapeless 是可能的:

import shapeless._

object _1 
object _2
object _3
object _4


//-------------Map definition starts here----------------
class StaticMap1[K, V]
trait StaticMap1Like {
  type M[T] <: StaticMap1[T, String]
  private def add[T]: M[T] = (new StaticMap1[T, String] {}).asInstanceOf[M[T]]

  implicit val __1 = add[_1.type] //add key to StaticMap1
  implicit val __2 = add[_2.type] //add key to StaticMap1
}
object StaticMap1 extends StaticMap1Like


val hm = HMap[StaticMap1](_1 -> "a", _2 -> "b") //add values
//-------------Map definition ends here-----------------

scala> hm.get(_1)
res0: Option[String] = Some(a)

scala> hm.get(_2)
res1: Option[String] = Some(b)

scala> hm.get(_3) //compile-time error
<console>:18: error: could not find implicit value for parameter ev: BiMapIS[shapeless.nat._3,V]
              hm.get(_3)
                    ^

和键插入:

//----Adding element _3 -> "c" starts here--------------
class StaticMap2[K, V] extends StaticMap1[K, V]
trait StaticMap2Like extends StaticMap1Like {
  type M[T] <: StaticMap2[T, String]
  private def add[T] = new StaticMap2[T, String] {}.asInstanceOf[M[T]]
  implicit val __3 = add[_3.type] //add key to StaticMap2
}
object StaticMap2 extends StaticMap2Like

val hm2 = hm.asInstanceOf[HMap[StaticMap2]] + (_3 -> "c")
//----Adding element ends here---------------------------

scala> hm2.get(_3)
res6: Option[String] = Some(c)

scala> hm2.get(_2)
res7: Option[String] = Some(b)

scala> hm2.get(_1)
res8: Option[String] = Some(a)

scala> hm2.get(_4)
<console>:21: error: could not find implicit value for parameter ev: StaticMap2[_4.type,V]
          hm2.get(_4)
                 ^

scala> hm.get(_3) //old `hm` still working
<console>:17: error: could not find implicit value for parameter ev: StaticMap1[_3.type,V]
          hm.get(_3)
                ^

但是:

  • 不要在这里使用 Shapeless native nat - 它不会工作,因为它无法区分 nat._1nat._2(至少对于我的 Shapeless 版本)
  • Map 添加元素也不会那么方便,因为用户将不得不为每个新键添加一个隐含的