【发布时间】:2021-05-06 17:25:10
【问题描述】:
我有一个类型 T 已知反射运行时作为 scala.reflect.runtime.Type 的值。我想创建一个代表scala.collection.Seq[T] 的类型值。我该怎么做?
我想要这个的背景:
我希望能够提取包含在各种类型的伴随对象中的反射泛型类型。这些类型的形式为type As[T] = T 或type As[T] = Seq[T]。对于任何X,我希望能够以X 或Seq[X] 的形式获得具体类型。第一种情况已经对我有用,因为在这种情况下,我只需返回我已经拥有的X 的Type。第二种情况更难 - 我有一个Type 用于Seq[T],这是通用的,Type 用于具体X,但我不知道如何修改我已经拥有或创建的Seq[T]一个全新的Seq[X]。
import scala.reflect.runtime.universe._
object Wrap {
type As[T] = T
}
case class Wrap[T](value: T)
object WrapSeq {
type As[T] = Seq[T]
}
case class WrapSeq[T](value: Seq[T])
object Main extends App {
def checkType(typeSignature: Type): Type = {
// find mapping in the companion object
val companion = typeSignature.typeSymbol.companion
val member = companion.typeSignature.member(TypeName("As"))
if (member != NoSymbol && member.isType) {
val memberType = member.asType
def extractSingleType(types: Seq[Type]): Option[Type] = types match {
case Seq(head) => Some(head)
case _ => None
}
(memberType.typeParams, typeSignature.typeArgs) match {
case (Seq(typePar), Seq(typeArg)) if memberType.isAliasType =>
if (member.typeSignature.resultType.typeSymbol.fullName == typePar.fullName) {
// As[T] == T
typeArg
} else if (member.typeSignature.resultType.typeSymbol.fullName == "scala.collection.Seq" && extractSingleType(member.typeSignature.resultType.typeArgs).exists(_.typeSymbol.name == typePar.name)) {
// As[T] == Seq[T]
// we want to return Seq[typeArg] here
// we need to construct the type reflectively somehow
???
} else {
throw new UnsupportedOperationException(s"Unsupported As value $typePar for $typeSignature")
}
case _ => // no type parameter, handle the plain type
member.typeSignature
}
} else {
typeSignature
}
}
println(checkType(typeOf[Wrap[String]])) // output: String
println(checkType(typeOf[WrapSeq[String]])) // desired output: Seq[String]
}
【问题讨论】:
-
你实际上想达到什么目标?
-
我正在为我序列化的类创建一个 JSON 模式。
As类型别名用于描述序列化编码器结果(编码器为 Borer 或 Circe)。 -
如果您知道您尝试序列化的类的类型,您不妨使用编译时反射。这样您就不会遇到类型擦除问题
-
是的,这是另一种解决方案(它有其自身的复杂性)。在我尝试这种方式之前,我正在检查反射是否可以得到我需要的东西。上面的代码已经处理了类型擦除(我有我需要的具体类型)。它是“唯一”构建
Seq[X],我想念它完全正常工作。 -
如果您正在考虑 hacky 解决方案,您可以将运行时类型的
X存储在包装器伴侣中。
标签: scala types reflection