1

这是一个后续问题:

如何在编译时使用无形获取案例类字段的名称作为字符串/符号?

假设我想写一个可以转换产品类型的递归转换器:

case class Prod (
  a: Int,
  b: String
)

进入记录,但与使用每个案例类字段(a,b)作为键的上述问题不同,我想直接使用每个类名或类型/类型构造函数名称。所以这个产品类型在编译时变成了一个记录:

"Int" ->> Int
"String" ->> String

(可能不是一个足够好的用例,但你明白了)

其中一个关键步骤是在编译时使用反射来获取每个类的名称,并将它们转换为 Singleton 类型或无形见证。我想知道这个功能是否已经在某处提供?还是我绝对需要一个白盒宏来实现它?

4

1 回答 1

2

你必须写一个宏

import shapeless.ops.hlist.Mapper
import shapeless.{Generic, HList, Poly1, Typeable}
import scala.language.experimental.macros
import scala.reflect.macros.whitebox

trait FieldTypes[A <: Product] {
  type Out <: HList
}
object FieldTypes {
  type Aux[A <: Product, Out0 <: HList] = FieldTypes[A] { type Out = Out0 }

  implicit def mkFieldTypes[A <: Product, L <: HList](implicit
    generic: Generic.Aux[A, L],
    mapper: Mapper[typeablePoly.type, L]
  ): Aux[A, mapper.Out] = null

  object typeablePoly extends Poly1 {
    implicit def cse[A](implicit typeable: Typeable[A]): Case[A] = macro cseImpl[A]
    def cseImpl[A: c.WeakTypeTag](c: whitebox.Context)(typeable: c.Tree): c.Tree = {
      import c.universe._
      val str = c.eval(c.Expr[String](c.untypecheck(q"$typeable.describe")))
      val tpA = weakTypeOf[A]
      q"null.asInstanceOf[FieldTypes.typeablePoly.Case.Aux[$tpA, _root_.shapeless.labelled.FieldType[$str, $tpA]]]"
    }
  }
}

测试:

import shapeless.{HNil, ::}
import shapeless.labelled.FieldType

implicitly[FieldTypes.Aux[Prod, FieldType["Int", Int] :: FieldType["String", String] :: HNil]]
于 2021-03-28T14:15:05.833 回答