Scala 如何使用shapeless在编译时将类名作为字符串文本获取?
这是以下问题的后续问题: 假设我想编写一个可以转换产品类型的递归转换器:Scala 如何使用shapeless在编译时将类名作为字符串文本获取?,scala,shapeless,scala-reflect,singleton-type,scala-2.13,Scala,Shapeless,Scala Reflect,Singleton Type,Scala 2.13,这是以下问题的后续问题: 假设我想编写一个可以转换产品类型的递归转换器: 案例类产品( 答:Int, b:字符串 ) 但与上面的问题不同,上面的问题使用每个case类字段(a,b)作为键,我想直接使用每个类名或类型/类型构造函数名。因此,此产品类型在编译时成为记录: "Int" ->> Int "String" ->> String (可能不是一个足够好的用例,但您已经有了想法) 其中一个关键步骤是使用反射在编译时获取每个类的
案例类产品(
答:Int,
b:字符串
)
但与上面的问题不同,上面的问题使用每个case类字段(a,b)作为键,我想直接使用每个类名或类型/类型构造函数名。因此,此产品类型在编译时成为记录:
"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]]]"
}
}
}
哇,好的。我将设法将您的代码合并到singleton ops中(显然已解决了所有应得的积分)。但是,让我们把它挂上几个星期,看看是否还有一件事会出现一个愚蠢友好的回答。答案可能缺少一个片段,当您将
隐式[…
分配给一个值时,它将导致编译错误:无法找到参数e:org.shapesafe.m.FieldTypes.Aux[
@tribbloid]的隐式值好吧,如果隐式[X]
在val X=隐式[X]编译时进行编译,那就很奇怪了
不会。别忘了,字段类型
和隐式地…
必须在不同的子项目中(就像Scala 2中的宏一样)?我不能在Scastie上准备代码片段,因为它不支持多个子项目。我可以在Github上发布。是的,这很奇怪()可能是一个编译器错误。不过Bloop/BSP可以很好地编译它
import shapeless.{HNil, ::}
import shapeless.labelled.FieldType
implicitly[FieldTypes.Aux[Prod, FieldType["Int", Int] :: FieldType["String", String] :: HNil]]