我正在开发一个涉及从Map[String, Any]
到一些案例类的大量序列化/反序列化的项目。我们通常知道密钥的类型是什么,因此我们使用unchecked
并指出其他地方没有会导致ClassCastException
的错误,就像在这个简单的示例中一样:
def myIntParser(in: Map[String, Any]): Map[String, Int] = in match {
case out: Map[String, Int @unchecked] => out
}
当然,这是scala,我相信我们可以做得更好。我的问题是如何编写以下函数:
// Returns Some(out) if 'in' can be safely cast as T,
// or None if in's type is not upper-bounded by T.
def safeCast[T: TypeTag](in: Any): Option[T] = ???
为了简化,我们的应用程序仅使用原始类型,地图,列表,选项和案例类,对其字段具有相同的限制。遍历所有结构,拆包等的成本被认为是微不足道的。
这是我目前的尝试,在SO上使用其他一些答案。它失败了,因为我不知道如何将对象的类与类型符号进行比较:
import scala.reflect.runtime.universe._
import scala.reflect._
// For early return
class CastFailException extends Exception("")
@throws[CastFailException]
def safeCastInternal[T](x: Any)(implicit ttag: TypeTag[T]): T = {
val ev = typeOf[T]
x match {
case it: Iterable[_] if ev <:< typeOf[Iterable[Any]] =>
val innerTpes = ev match {
case TypeRef(_, _, args) => args
}
val innerTpe = innerTpes.headOption.getOrElse(throw new CastFailException)
val tt = backward[Any](innerTpe)
it.toList.map(x => safeCastInternal(x)(tt)).asInstanceOf[T]
case y => ???
}
}
val universe = scala.reflect.runtime.universe
val mirror = runtimeMirror(getClass.getClassLoader)
// From another SO question
def backward[T](tpe: Type): TypeTag[T] =
TypeTag(mirror, new api.TypeCreator {
def apply[U <: api.Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U # Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
提前致谢!