如何使用scala准引号动态生成类型应用程序



我想生成一个类型应用程序,这样我就可以调用像foo.bar[com.a.b.SomeType](baz)这样的函数,其中com.a.b.SomeType可以是各种类型中的任何一种。我在宏运行时中使用反射来获得对SomeType表示的实际类的引用,这样我就可以获得包名称、简单名称和完全限定名称。

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

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

我需要使用类信息动态创建tq表达式,这些类信息可以从宏运行时中的字符串中获得。我查看了tq"com.example.SomeType"生成的树,每个包com、a、b、c都有一系列嵌套的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的实例(获得的情况下,有什么简洁的方法可以实现我想要做的事情呢?

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

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将确保您不是在使用已知类型,而是使用来自类型参数而不是凭空产生的东西(。

相关内容

  • 没有找到相关文章

最新更新