我正在玩Scala TypeTag。我想以递归方式调用带有TypeTag参数的函数。以下是我正在尝试做的简化示例:
import scala.reflect.runtime.universe._
object TypeTagTest extends App {
def intValue[T](value: T)(implicit tag: TypeTag[T]): Int = {
tag.tpe match {
// integer
case intType if intType <:< typeOf[Int] =>
value.asInstanceOf[Int]
// string
case stringType if stringType <:< typeOf[String] =>
value.asInstanceOf[String].toInt
// option of either string or integer
case optionType @ TypeRef(_, _, typeArg::Nil) if optionType <:< typeOf[Option[_]] =>
println(s"Unwrapped type is $typeArg")
val option = value.asInstanceOf[Option[_]]
option.map { optionValue =>
// how to pass the typeArg here?
intValue(optionValue)
}.getOrElse(0)
}
}
println(intValue(1))
println(intValue("1"))
println(intValue(Some("1")))
}
此代码编译并运行:
1
1
Exception in thread "main" scala.MatchError: Any (of class scala.reflect.internal.Types$TypeRef$$anon$6)
at TypeTagTest$.intValue(TypeTagTest.scala:7)
at TypeTagTest$$anonfun$intValue$2.apply(TypeTagTest.scala:19)
at TypeTagTest$$anonfun$intValue$2.apply(TypeTagTest.scala:18)
at scala.Option.map(Option.scala:145)
几个问题:
答案 0 :(得分:0)
这不是递归问题 - 您的“Unwrapped type ...”行永远不会打印。我怀疑问题在于optionType
,在这种情况下Some[String]
,不是Option[_]
的严格子类型,它扩展为Option[A] forSome {type A}
。
在这个特定的例子中,您可能希望测试optionType <:< Option[Any]
是否Option
,因为TypeRef
是协变的?或许您可以检查Option
的第一个参数是TypeTag
。
一旦你修复了它,我认为不可能获得参数的Type
,因为它们总是由编译器生成,但是因为你只使用{{1}你可以让这个方法适用于那些:
def intValueInner(value: Any, tpe: Type) = tpe match {
...
case optionType @ TypeRef(_, _, typeArg::Nil) if optionType <:< typeOf[Option[Any]] =>
value.asInstanceOf[Option[_]].map(v => intValueInner(v, typeArg)).getOrElse(0)
}
def intValue[T: TypeTag](t: T) = intValueInner(t, typeOf[T])