从Class [T]映射到T而不进行强制转换

mic*_*hid 7 scala

我想从类标记映射到以下代码行的实例:

trait Instances {
  def put[T](key: Class[T], value: T)
  def get[T](key: Class[T]): T
}
Run Code Online (Sandbox Code Playgroud)

这可以在不必解析get方法中的强制转换的情况下完成吗?

更新:

对于更普遍的情况,如何用一些Foo[T]而不是Class[T]

Jea*_*let 9

您可以尝试从地图中检索对象Any,然后使用Class[T]"反射性地":

trait Instances {                                        
  private val map = collection.mutable.Map[Class[_], Any]()
  def put[T](key: Class[T], value: T) { map += (key -> value) }
  def get[T](key: Class[T]): T = key.cast(map(key))        
}
Run Code Online (Sandbox Code Playgroud)


Uda*_*ala 5

在我的一个朋友的帮助下,我们将键定义为Manifest而不是Class,这样可以在调用时提供更好的api.

我没有得到关于"一般案例与一些Foo [T]而不是Class [T]"的更新问题.但这适用于您指定的案例.

object Instances {                                        
  private val map = collection.mutable.Map[Manifest[_], Any]()
  def put[T: Manifest](value: T) = map += manifest[T] -> value
  def get[T: Manifest]: T = map(manifest[T]).asInstanceOf[T]

  def main (args: Array[String] ) {
    put(1)
    put("2")
    println(get[Int])
    println(get[String])
  }
}


Dan*_*wak 2

如果您想在不进行任何转换(即使在get)的情况下执行此操作,那么您将需要编写一个异构映射。由于显而易见的原因,这很棘手。:-) 最简单的方法可能是使用HList类似的结构并构建一个find函数。然而,这并不是微不足道的,因为您需要定义某种方法来检查两个任意类型的类型相等性。

我试图对元组和存在类型进行一些处理。但是,Scala 不提供统一机制(模式匹配不起作用)。此外,子类型将整个事情捆绑在一起,基本上消除了它可能提供的任何类型的安全性:

val xs: List[(Class[A], A) forSome { type A }] = List(
  classOf[String] -> "foo", classOf[Int] -> 42)

val search = classOf[String]
val finalResult = xs collect { case (`search`, result) => result } headOption
Run Code Online (Sandbox Code Playgroud)

在此示例中,finalResult将是 类型Any。这实际上是正确的,因为子类型意味着我们A. 这不是编译器选择该类型的原因,但它是一个正确的选择。举个例子:

val xs: List[(Class[A], A) forSome { type A }] = List(classOf[Boolean] -> 'bippy)
Run Code Online (Sandbox Code Playgroud)

这是完全合法的!子类型化意味着A在这种情况下将被选择为Any。这不是我们想要的,但这是您将得到的。因此,为了表达此约束而不跟踪所有单独的类型(使用HMap),Scala 需要能够表达类型是特定类型而不是其他类型的约束。不幸的是,Scala 没有这种能力,所以我们基本上停留在通用约束方面。

更新 实际上,这是不合法的。刚刚尝试了一下,编译器将其踢出。我认为这之所以有效,是因为Class它的类型参数是不变的。因此,如果Foo是一个不变的确定类型,那么您应该不会出现这种情况。它仍然没有解决统一问题,但至少是合理的。不幸的是,类型构造函数被认为处于同、反和不变性之间的神奇叠加,因此,如果它确实是任意类型Foo的 kind * => *,那么您仍然会陷入存在主义的困境。

总之:这应该是可能的,但前提是您完全编码InstancesHMap. 就我个人而言,我只会在里面投射get。简单多了!