scala:如何使用编译时宏通过复杂的多态性获取 class 名称?

scala: How to obtain class name through complex polymorphism with compile time macros?

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

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

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 class,并且它们可以报告其容器的名称,即用于一些元配置。基本上 MacroSupportGenericInterface 将存在于我正在编写的库中,而 FunctionalClassContainer 级别将由其他人使用该库编写。

我遇到的问题是由于 GenericInterfaceFunctionalClass.containerName == "t" 中的传递类型,并且尝试访问类型声明没有任何结果。如何从 FunctionalClass 声明到 MacroSupport 级别获取类型信息?

尝试 class

类型的具体化

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