微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从元组类型中提取类型?

如何解决如何从元组类型中提取类型?

我有一个密码

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

如果以智能方式评估表达式typeof[TT],我会看到属性args及其类型列表,但我不知道如何从代码访问。或者可以采用其他方法

预先感谢

解决方法

在编译时必须知道T中的

类型参数case 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,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,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,Boolean)]() // List(MyTypeTag(),MyTypeTag())

如果使MyTypeTag为协变(MyTypeTag[+T]),则List[MyTypeTag[_ <: Option[_]]]可以替换为List[MyTypeTag[Option[_]]]

,

您无法在运行时区分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获取类型参数,但是由于这是一个运行时值,因此无法将其作为T的编译时类型MyTypeTag[T]恢复,因为它不能还没有在编译时出现。

也许您可以利用无形来做您想做的任何事情,它有方法可以对元组进行抽象。参见https://underscore.io/books/shapeless-guide/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。