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

如何在编译时使用 shapeless 将类的名称作为字符串文字获取?

如何解决如何在编译时使用 shapeless 将类的名称作为字符串文字获取?

这是一个后续问题:

How to get the name of a case class field as a string/symbol at compile time using shapeless?

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

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

into a Record,但与上面使用每个 case 类字段 (a,b) 作为键的问题不同,我想直接使用每个类名或类型/类型构造函数名称。所以这个产品类型在编译时就变成了 Record:

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

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

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

解决方法

你必须写一个宏

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]]

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