2016-03-02 46 views
1

我的理解是TypeTags可以让我们在运行时恢复类型。但是,我使用集合参数与TypeTag[_]时,我不能这样做:如何使用类型标签在运行时恢复类型?

这是我第一次尝试:

import scala.reflect.runtime.universe._ 
import scala.collection.mutable 

type TaggedVal = Tuple2[TypeTag[_], Any] 
val tagMap: Map[Int, TaggedVal] = Map(
    0 -> (typeTag[Int], 12345), 
    1 -> (typeTag[String], "abcde") 
) 


def get[T](key: Int)(implicit tag: TypeTag[T]) = tagMap.get(key) match { 
    case Some((t, v)) => Some(v.asInstanceOf[T]) 
    case _ => None 
} 

implicit val zeroTag = tagMap(0)._1 
val zero = get(0).get 
val testing: Int = zero 

这将导致未能取回存储类型:

Error:(18, 26) type mismatch; 
found : Any 
required: Int 
lazy val testing: Int = zero 
        ^

第二个类似的尝试如下,但它导致匹配错误:

type TypedVal = Tuple2[Type, Any] 
val tagMap: mutable.Map[Int, TypedVal] = mutable.Map() 

def put[T: TypeTag](key: Int, value: T) = tagMap.put(key, (typeOf[T], value)) 

def get[T: TypeTag](key: Int) = tagMap.get(key).get match { 
    case tv: TypedVal if tv._1 =:= typeOf[T] => Some(tv._2.asInstanceOf[T]) 
} 

put(0, (typeOf[Int], 12345)) 
put(1, (typeOf[String], "abcde")) 
val zero = get(0).get 

有没有合理的方法可以做到这一点?

参考:How save a TypeTag and then use it later to reattach the type to an Any (Scala 2.10)

回答

1

您需要的类型参数自己提供给get,否则不能正常工作。你实质上是在编译时询问这个类型,而在运行时只知道它的类型。

type TaggedVal = (TypeTag[_], Any) 

val tagMap: Map[Int, TaggedVal] = Map(
    0 -> (typeTag[Int], 12345), 
    1 -> (typeTag[String], "abcde") 
) 

def get[T](key: Int)(implicit tag: TypeTag[T]): Option[T] = tagMap.get(key) match { 
    case Some((t, v)) if t.tpe =:= typeOf[T] => Some(v.asInstanceOf[T]) 
    case _ => None 
} 

scala> get[String](1) 
res31: Option[String] = Some(abcde) 

scala> get[Int](1) 
res32: Option[Int] = None 

类似以下(不强制类型参数),但是,不能正常工作,因为那是返回(通过铸造)类型是在运行时只知道。无法推断为i作为Int

val i = get(0).get 
val j: Int = i 
+0

内心深处,我想我知道是这样,但我想确定 - 谢谢。我结束了在案例类和类型类中包装我所需要的东西,以试图理解它 - 似乎到目前为止工作。 – bbarker