scala:如何通过带有编译时宏的复杂多态性获得类名?

时间:2019-04-21 06:34:22

标签: scala scala-macros

在定义宏实现时尝试通过WeakTypeTag引用获取类的名称时,如果应用了多层多态性,我似乎无法获得正确的信息。

例如,如果我具有以下设置:

object MacroSupport {
  def get_name_impl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[String] = {
    val nameOfA: String = weakTypeOf[A].toString
    ...
  }

  def getName[A] = macro get_name_impl[A]
}

abstract class GenericInterface[T] {
  def getName: String = MacroSupport.getName[T]
}

case class ContainerA(
  someValue: String
)

class FunctionalClass extends GenericInterface[ContainerA] {
  val containerName: String = getName
}

我希望实现的是拥有任意数量的FunctionalClass,每个都有自己的Container类,并且他们可以报告其容器的名称,该名称用于某些元配置。基本上MacroSupportGenericInterface将存在于我正在编写的库中,而FunctionalClassContainer级别将由使用该库的其他人编写。

由于GenericInterfaceFunctionalClass.containerName ==“ t”中的直通类型,我遇到的问题以及尝试访问Type声明均未产生任何问题。如何从FunctionalClass声明到MacroSupport级别获取类型信息?

1 个答案:

答案 0 :(得分:1)

尝试实现类的实现

https://docs.scala-lang.org/overviews/macros/implicits.html#implicit-materializers

import scala.reflect.macros.blackbox
import scala.language.experimental.macros

object MacroSupport {
  def getName[A](implicit gn: GetName[A]): String = gn()

  trait GetName[A] {
    def apply(): String
  }

  object GetName {
    implicit def materializeGetName[A]: GetName[A] = macro materializeGetNameImpl[A]

    def materializeGetNameImpl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[GetName[A]] = {
      import c.universe._

      c.Expr[GetName[A]] {
        q"""
          new MacroSupport.GetName[${weakTypeOf[A]}] {
             override def apply(): _root_.java.lang.String = ${weakTypeOf[A].toString}
          }
         """
      }
    }
  }
}

import MacroSupport.GetName

abstract class GenericInterface[T: GetName] {
  def getName: String = MacroSupport.getName[T]
}

case class ContainerA(
                      someValue: String
                     )

class FunctionalClass extends GenericInterface[ContainerA] {
  val containerName: String = getName
}

(new FunctionalClass).containerName // ContainerA

顺便说一下,shapeless.Typeable完成了这项工作。 Typeable[A].describe就像我们的MacroSupport.getName[A]