我正在尝试创建一个宏,以便为我提供特定案例类的val列表。
pyodbc
给定
Executed as user: DOMAIN\SQLUser. Traceback (most recent call last): File "PathToScript\script.py". line 1, in <module> import pyodbc ModuleNotFoundError: No module named 'pyodbc'.
我想要一个object CaseClass {
def valList[T]: List[String] = macro implValList[T]
def implValList[T](c: whitebox.Context): c.Expr[List[String]] = {
import c.universe._
val listApply = Select(reify(List).tree, TermName("apply"))
val vals = weakTypeOf[T].decls.collect {
case m: TermSymbol if m.isVal => q"${m.name}"
}
c.Expr[List[String]](Apply(listApply, vals.toList))
}
}
答案 0 :(得分:1)
不是宏专家,所以要加些盐。但是我用Intellij进行了测试。
首先,要使用weakTypeOf
,您需要将WeakTypeTag
作为宏隐式中的隐式对象,如下所示:
def implValList[T](c: whitebox.Context)(implicit wt: c.WeakTypeTag[T]) ...
第二,要创建文字,请使用此构造代替准引用(我相信实际上什么也没做):
Literal(Constant(m.name.toString))
最后,我建议使用此防护而不是isVal
:
m.isCaseAccessor && m.isGetter
这将正确地检查案例类参数,并且也是一个吸气剂(案例类参数重复,一个作为isGetter
,另一个作为isParam
)。原因是案例类的isVal
名称令人惊讶地产生了以空格结尾的名称。
对我有用的最终实现如下:
object CaseClass {
def valList[T]: List[String] = macro implValList[T]
def implValList[T](c: whitebox.Context)(implicit wt: c.WeakTypeTag[T]): c.Expr[List[String]] = {
import c.universe._
val listApply = Select(reify(List).tree, TermName("apply"))
val vals = weakTypeOf[T].decls.collect {
case m: TermSymbol if m.isCaseAccessor && m.isGetter => Literal(Constant(m.name.toString))
}
c.Expr[List[String]](Apply(listApply, vals.toList))
}
}
作为一种替代方法(因为宏的设置有些麻烦-您不能在定义宏的同一子项目中使用宏),而且您不需要的频率很高,因此也许可以摆脱shapeless单线:
import shapeless._
import shapeless.ops.record.Keys
case class Foo(a: Int, b: String)
Keys[the.`LabelledGeneric[Foo]`.Repr].apply().toList.map(_.name) // List("a", "b")