Context:我正在尝试编写一个静态地知道非固定数量类型的宏。我正在尝试使用HList
将这些类型作为单个类型参数传递。它将被称为m[ConcreteType1 :: ConcreteType2 :: ... :: HNil]()
。然后,宏会构建一个match语句,该语句要求在编译时找到一些隐式对象,就像json序列化程序可能需要隐式编码器一样。当在固定数量的类型参数上使用宏时,我有一个有效的宏实现,如下所示:
def m[T1, T2](): Int = macro mImpl[T1, T2]
def mImpl[T1: c.WeakTypeTag, T2: c.WeakTypeTag](c: Context)(): c.Expr[Int] = {
import c.universe._
val t = Seq(
weakTypeOf[T1],
weakTypeOf[T2]
).map(c => cq"a: $c => externalGenericCallRequiringImplicitsAndReturningInt(a)")
val cases = q"input match { case ..$t }"
c.Expr[Int](cases)
}
问题:如果我的某个WeakTypeTag[T]
有一个T <: HList
,是否有任何方法可以将其转换为Seq[Type]
?
def hlistToSeq[T <: HList](hlistType: WeakTypeTag[T]): Seq[Type] = ???
我的直觉是编写一个递归匹配,将每个T <: HList
转换为H :: T
或HNil
,但我认为Scala中不存在这种匹配。
[我想知道有其他方法可以将任意大小的类型的列表放入宏,请记住,我需要Seq[Type]
而不是Expr[Seq[Type]]
,因为我需要在它们上进行映射宏代码。
用Dotty编写类似的'macro'的方法也很有趣-我希望在那里会更简单,但是还没有完全研究。
Edit(clarification):我使用宏的原因是我希望我正在编写的库的用户提供类型的集合(也许以HList
的形式),库可以迭代并期望与之相关的隐式对象。我说的是库,但是它将与用途一起编译,以便运行宏。在任何情况下,它都可以与不同的类型集合一起重用。这有点令人困惑,但是我想我已经解决了这一点-我只需要能够构建可以对类型列表进行操作的宏即可。
当前您似乎不需要宏。似乎类型类或shapeless.Poly
就足够了。
def externalGenericCallRequiringImplicitsAndReturningInt[C](a: C)(implicit
mtc: MyTypeclass[C]): Int = mtc.anInt
trait MyTypeclass[C] {
def anInt: Int
}
object MyTypeclass {
implicit val mtc1: MyTypeclass[ConcreteType1] = new MyTypeclass[ConcreteType1] {
override val anInt: Int = 1
}
implicit val mtc2: MyTypeclass[ConcreteType2] = new MyTypeclass[ConcreteType2] {
override val anInt: Int = 2
}
//...
}
val a1: ConcreteType1 = null
val a2: ConcreteType2 = null
externalGenericCallRequiringImplicitsAndReturningInt(a1) //1
externalGenericCallRequiringImplicitsAndReturningInt(a2) //2