scala - 如何从元组类型中提取类型?
问题描述
我有一个代码
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
带有我的类型列表的属性,但我不知道如何从代码中访问。或者可以采用其他一些方法。
提前致谢
解决方案
类型参数T
incase class MyTypeTag[T]()
必须在编译时知道。但是您似乎尝试使用运行时反射来定义它。这是行不通的(除非您在运行时定义类:toolbox.define(q"case class MyTypeTag[T]()")
但这会很棘手)。
您可以尝试使用编译时反射
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[_]]]
.
推荐阅读
- c# - 一旦该属性已被传递给 C# 中的函数,如何更改该属性
- azure - 如何在客户端机器中隐藏用于加密的私钥?
- javascript - CSS Flex-box justify-self / align-self 不起作用
- mongodb - 如何在mongodb中查询过去六个月的日期
- azure - 在 AKS 群集下的 devspaces 中运行应用程序时出现问题
- amazon-web-services - 我可以使用 aws 中的 ssl 而不是让地址(ip)本身加密吗?
- perl - 我们可以使用不带前缀的 perl 包变量,只在该包中使用范围吗?
- php - Copy and paste values from 2 differents db with a button
- pm2 - 如何使用 pm2 启动带有 AutoReload 的strapi?
- python - 将 numpy memmap 保存到新文件并从该文件加载新的 memmap 会导致值更改