从宏中的 HList 获取类型序列
Get sequence of types from HList in macro
Context:我正在尝试编写一个静态识别非固定数量类型的宏。我正在尝试使用 HList
将这些类型作为单个类型参数传递。它将被称为 m[ConcreteType1 :: ConcreteType2 :: ... :: HNil]()
。然后宏构建一个匹配语句,它需要在编译时找到一些隐式,有点像 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' 的方法也很有趣 - 我希望它会更简单,但还没有完全研究。
编辑(澄清):我使用宏的原因是我希望我正在编写的库的用户提供类型的集合(也许在HList
的形式),库可以对其进行迭代并期望与之相关的隐式。我说的是library,但是它会和uses一起编译,为了宏运行;在任何情况下,它都应该可以与不同的类型集合一起使用。这有点令人困惑,但我想我已经解决了这一点 - 我只需要能够构建可以对类型列表进行操作的宏。
目前您似乎不需要宏。似乎输入 类 或 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
Context:我正在尝试编写一个静态识别非固定数量类型的宏。我正在尝试使用 HList
将这些类型作为单个类型参数传递。它将被称为 m[ConcreteType1 :: ConcreteType2 :: ... :: HNil]()
。然后宏构建一个匹配语句,它需要在编译时找到一些隐式,有点像 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' 的方法也很有趣 - 我希望它会更简单,但还没有完全研究。
编辑(澄清):我使用宏的原因是我希望我正在编写的库的用户提供类型的集合(也许在HList
的形式),库可以对其进行迭代并期望与之相关的隐式。我说的是library,但是它会和uses一起编译,为了宏运行;在任何情况下,它都应该可以与不同的类型集合一起使用。这有点令人困惑,但我想我已经解决了这一点 - 我只需要能够构建可以对类型列表进行操作的宏。
目前您似乎不需要宏。似乎输入 类 或 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