我有一个带有值的通用映射,其中一些可以依次列出值。 我正在尝试处理给定的密钥并将结果转换为外部调用者所期望的类型,如下所示:
// A map with some values being other collections.
val map: Map[String, Any] = Map("foo" -> 1, "bar" -> Seq('a', 'b'. 'a'))
// A generic method with a "specialization" for collections (pseudocode)
def cast[T](key: String) = map.get(key).map(_.asInstanceOf[T])
def cast[C <: Iterable[T]](key: String) = map.get(key).map(list => list.to[C].map(_.asIntanceOf[T]))
// Expected usage
cast[Int]("foo") // Should return 1:Int
cast[Set[Char]]("bar") // Should return Set[Char]('a', 'b')
这是为了表明我想做什么,但它不起作用。编译器错误抱怨(正确地,大约2个可能的匹配)。我也尝试将这个单一的函数与类型上的某种模式匹配无效。
我一直在阅读@specialized,TypeTag,CanBuildFrom和其他scala功能,但我找不到一个简单的方法将它们放在一起。我发现的单独示例涉及不同的部分和一些丑陋的变通方法,但没有任何简单地允许外部用户调用cast
并获得异常的情况是演员表无效。有些东西也很旧,我正在使用Scala 2.10.5。
答案 0 :(得分:1)
这似乎有效,但有一些问题。
def cast[T](m: Map[String, Any], k: String):T = m(k) match {
case x: T => x
}
使用正确的输入,您将获得正确的输出。
scala> cast[Int](map,"foo")
res18: Int = 1
scala> cast[Set[Char]](map,"bar")
res19: Set[Char] = Set(a, b)
但如果键的类型错误或地图没有这样的键(当然),它会抛出。
答案 1 :(得分:1)
您可以通过隐式参数执行此操作:
val map: Map[String, Any] = Map("foo" -> 1, "bar" -> Set('a', 'b'))
abstract class Casts[B] {def cast(a: Any): B}
implicit val doubleCast = new Casts[Double] {
override def cast(a: Any): Double = a match {
case x: Int => x.toDouble
}
}
implicit val intCast = new Casts[Int] {
override def cast(a: Any): Int = a match {
case x: Int => x
case x: Double => x.toInt
}
}
implicit val seqCharCast = new Casts[Seq[Char]] {
override def cast(a: Any): Seq[Char] = a match {
case x: Set[Char] => x.toSeq
case x: Seq[Char] => x
}
}
def cast[T](key: String)(implicit p:Casts[T]) = p.cast(map(key))
println(cast[Double]("foo")) // <- 1.0
println(cast[Int]("foo")) // <- 1
println(cast[Seq[Char]]("bar")) // <- ArrayBuffer(a, b) which is Seq(a, b)
但你仍然需要迭代所有类型到类型的选项,这是合理的Set('a', 'b').asInstanceOf[Seq[Char]]
抛出,并且你不能使用通用强制转换,所以你需要以不同的方式处理这种情况。
听起来有点矫枉过正,你可能需要从全球角度审视你的方法