0

我想生成一个类型应用程序,这样我就可以调用一个函数,比如foo.bar[com.a.b.SomeType](baz)wherecom.a.b.SomeType可以是多种类型中的任何一种。我在宏运行时使用反射来获取对由 表示的实际类的引用,SomeType因此我可以执行诸如获取包名称、简单名称和完全限定名称之类的操作。

当我写作时,tq"com.a.b.SomeType"我得到了想要的结果,并且可以在我的表达式中使用插值,例如

val someType = tq"com.a.b.SomeType"
q"""
  foo.bar[$someType](baz)
"""

我需要tq使用可以从宏运行时中从字符串中获取的类信息来动态创建该表达式。我查看了生成的树,每个包 com、a、b、ctq"com.example.SomeType"都有一系列嵌套Select节点,手动生成似乎很麻烦。

Select(Select(Select(Ident(TermName("com")), TermName("a")), TermName("b")), TypeName("SomeType"))

我想有一种更简单的方法,我只是没有看到。

为此,我尝试了以下方法:

tq"${someType.getPackage.getName}.${someType.getSimpleName}"

但我可以看到这是不对的,并得到如下错误:

Compilation error[MyMacro.this.c.universe.Name expected but MyMacro.this.c.universe.Tree found]

那么在类型名称只能通过反射获得的情况下,实现我想要做的事情的简洁方法是什么,例如作为Class?

4

1 回答 1

1

您无法从运行时反射中获取类型,因为此类型将在生成的代码中使用并以二进制形式出现。TypeTag但是,您可以使用或从调用站点获取编译时的类型WeakTypeTag

def myMethod[T] = macro macroImplementation

def macroImplementation[T: c.WeakTypeTag](c: Context) = {
  val typeT = weakTypeOf[T].tpe
  val body = q"""
    foo.bar[$typeT](baz)
  """
  ...
}

这应该允许您为具有类型参数的方法创建宏,您可以安全地填写运行时(这typeT将确保您使用的不是已知类型,而是使用来自类型参数而不是来自稀薄的空气)。

于 2020-04-02T09:30:28.607 回答