如何从元组类型中提取类型?
How to extract types from tuple type?
我有密码
case class MyTypeTag[T] ()
def getTypeTags[TT <: Product : TypeTag] = {
val subtypesTags: List[MyTypeTag[Option[_]] = ???
sybtypesTags
}
val res = getTypeTags[(Int, String, Boolean)]
// res = MyTypeTag[Option[Int]] :: MyTypeTag[Option[String]] :: MyTypeTag[Option[Boolean]] :: Nil
所以我想调用函数 getTypeTags
将任何元组类型作为类型参数传递并获取 MyTypeTag
实例列表,每个类型包含在 Option
中
如果在 intelliJ 中我评估表达式 typeof[TT]
我看到 属性 args
和我的类型列表,但我不知道如何从代码访问。或者可能还有其他一些方法可以应用。
提前致谢
您无法在运行时区分 MyTypeTag[Int]
的实例和 MyTypeTag[String]
的实例(要自己检查,请尝试
val l = List(MyTypeTag[Option[Int]](), MyTypeTag[Option[String]](), MyTypeTag[Option[Boolean]]())
看看它能给你带来什么,你能用它做什么,不能用它做什么),所以你问的问题的答案是
def getTypeTags[TT <: Product](implicit tt: TypeTag[TT]): List[MyTypeTag[_]] = {
tt.tpe.typeParams.map(_ => MyTypeTag[Option[_]]())
}
您可以使用 tt.tpe.typeParams
获取类型参数,但由于这是一个运行时值,您无法将其恢复为 compile-time 类型 T
for MyTypeTag[T]
因为它在 compile-time 还不存在。
也许你可以利用 shapeless 来做你想做的任何事情,它有办法对元组进行抽象。参见 https://underscore.io/books/shapeless-guide/
case class MyTypeTag[T]()
中的类型参数 T
必须在编译时已知。但是您似乎尝试使用运行时反射来定义它。这行不通(除非您在运行时定义 class:toolbox.define(q"case class MyTypeTag[T]()")
但这会很棘手)。
你可以尝试使用compile-time反射
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def getTypeTags[TT <: Product]: List[MyTypeTag[_ <: Option[_]]] =
macro getTypeTagsImpl[TT]
def getTypeTagsImpl[TT: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
weakTypeOf[TT].typeArgs.map(t => q"MyTypeTag[Option[$t]]()")
.foldRight[Tree](q"Nil")((t, ts) => q"$t :: $ts")
}
用法:
getTypeTags[(Int, String, Boolean)] //List(MyTypeTag(), MyTypeTag(), MyTypeTag())
为了验证代码是否正常,我们临时修改一下MyTypeTag
import scala.reflect.runtime.universe.TypeTag
case class MyTypeTag[T]()(implicit val typeTag: TypeTag[T])
val res = getTypeTags[(Int, String, Boolean)]
res(0).typeTag // TypeTag[Option[Int]]
res(1).typeTag // TypeTag[Option[String]]
res(2).typeTag // TypeTag[Option[Boolean]]
你也可以使用 Shapeless 而不是宏
import shapeless.ops.hlist.{FillWith, Mapped, ToList}
import shapeless.{Generic, HList, Poly0}
case class MyTypeTag[T]()
def getTypeTags[TT <: Product] = new {
def apply[L <: HList, L1 <: HList]()(implicit
generic: Generic.Aux[TT, L],
mapped: Mapped.Aux[L, λ[X => MyTypeTag[Option[X]]], L1],
fillWith: FillWith[myTypeTagPoly.type, L1],
toList: ToList[L1, MyTypeTag[_ <: Option[_]]]
): List[MyTypeTag[_ <: Option[_]]] =
fillWith().toList
}
object myTypeTagPoly extends Poly0 {
implicit def cse[A]: Case0[MyTypeTag[Option[A]]] = at(MyTypeTag[Option[A]]())
}
getTypeTags[(Int, String, Boolean)]() // List(MyTypeTag(), MyTypeTag(), MyTypeTag())
如果使 MyTypeTag
协变 (MyTypeTag[+T]
),则 List[MyTypeTag[_ <: Option[_]]]
可以替换为 List[MyTypeTag[Option[_]]]
。
我有密码
case class MyTypeTag[T] ()
def getTypeTags[TT <: Product : TypeTag] = {
val subtypesTags: List[MyTypeTag[Option[_]] = ???
sybtypesTags
}
val res = getTypeTags[(Int, String, Boolean)]
// res = MyTypeTag[Option[Int]] :: MyTypeTag[Option[String]] :: MyTypeTag[Option[Boolean]] :: Nil
所以我想调用函数 getTypeTags
将任何元组类型作为类型参数传递并获取 MyTypeTag
实例列表,每个类型包含在 Option
如果在 intelliJ 中我评估表达式 typeof[TT]
我看到 属性 args
和我的类型列表,但我不知道如何从代码访问。或者可能还有其他一些方法可以应用。
提前致谢
您无法在运行时区分 MyTypeTag[Int]
的实例和 MyTypeTag[String]
的实例(要自己检查,请尝试
val l = List(MyTypeTag[Option[Int]](), MyTypeTag[Option[String]](), MyTypeTag[Option[Boolean]]())
看看它能给你带来什么,你能用它做什么,不能用它做什么),所以你问的问题的答案是
def getTypeTags[TT <: Product](implicit tt: TypeTag[TT]): List[MyTypeTag[_]] = {
tt.tpe.typeParams.map(_ => MyTypeTag[Option[_]]())
}
您可以使用 tt.tpe.typeParams
获取类型参数,但由于这是一个运行时值,您无法将其恢复为 compile-time 类型 T
for MyTypeTag[T]
因为它在 compile-time 还不存在。
也许你可以利用 shapeless 来做你想做的任何事情,它有办法对元组进行抽象。参见 https://underscore.io/books/shapeless-guide/
case class MyTypeTag[T]()
中的类型参数 T
必须在编译时已知。但是您似乎尝试使用运行时反射来定义它。这行不通(除非您在运行时定义 class:toolbox.define(q"case class MyTypeTag[T]()")
但这会很棘手)。
你可以尝试使用compile-time反射
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def getTypeTags[TT <: Product]: List[MyTypeTag[_ <: Option[_]]] =
macro getTypeTagsImpl[TT]
def getTypeTagsImpl[TT: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
weakTypeOf[TT].typeArgs.map(t => q"MyTypeTag[Option[$t]]()")
.foldRight[Tree](q"Nil")((t, ts) => q"$t :: $ts")
}
用法:
getTypeTags[(Int, String, Boolean)] //List(MyTypeTag(), MyTypeTag(), MyTypeTag())
为了验证代码是否正常,我们临时修改一下MyTypeTag
import scala.reflect.runtime.universe.TypeTag
case class MyTypeTag[T]()(implicit val typeTag: TypeTag[T])
val res = getTypeTags[(Int, String, Boolean)]
res(0).typeTag // TypeTag[Option[Int]]
res(1).typeTag // TypeTag[Option[String]]
res(2).typeTag // TypeTag[Option[Boolean]]
你也可以使用 Shapeless 而不是宏
import shapeless.ops.hlist.{FillWith, Mapped, ToList}
import shapeless.{Generic, HList, Poly0}
case class MyTypeTag[T]()
def getTypeTags[TT <: Product] = new {
def apply[L <: HList, L1 <: HList]()(implicit
generic: Generic.Aux[TT, L],
mapped: Mapped.Aux[L, λ[X => MyTypeTag[Option[X]]], L1],
fillWith: FillWith[myTypeTagPoly.type, L1],
toList: ToList[L1, MyTypeTag[_ <: Option[_]]]
): List[MyTypeTag[_ <: Option[_]]] =
fillWith().toList
}
object myTypeTagPoly extends Poly0 {
implicit def cse[A]: Case0[MyTypeTag[Option[A]]] = at(MyTypeTag[Option[A]]())
}
getTypeTags[(Int, String, Boolean)]() // List(MyTypeTag(), MyTypeTag(), MyTypeTag())
如果使 MyTypeTag
协变 (MyTypeTag[+T]
),则 List[MyTypeTag[_ <: Option[_]]]
可以替换为 List[MyTypeTag[Option[_]]]
。