如何在案例类中创建宏以创建val列表?

时间:2018-12-21 17:47:49

标签: scala macros reflect

我正在尝试创建一个宏,以便为我提供特定案例类的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)) } }

的列表

1 个答案:

答案 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")