我想生成一个类型应用程序,这样我就可以调用像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
的实例(获得的情况下,有什么简洁的方法可以实现我想要做的事情呢?
您无法从运行时反射中获取类型,因为此类型将在生成的代码中使用,并以二进制形式登录。但是,您可以在编译时使用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
将确保您不是在使用已知类型,而是使用来自类型参数而不是凭空产生的东西(。