【问题标题】:How to create a Macro to create List of val in a case class?如何创建宏以在案例类中创建 val 列表?
【发布时间】:2018-12-21 17:47:48
【问题描述】:

我正在尝试创建一个宏来为我提供特定案例类的 val 列表。

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))
  }

}

给定

case class AClass(
   val a: String,
   val b: Int
)

我想要CaseClass.valList[AClass] = List("a", "b")的列表

【问题讨论】:

    标签: scala macros reflect


    【解决方案1】:

    不是宏方面的专家,所以对它持保留态度。但我用 Intellij 对其进行了测试。

    首先,要使用weakTypeOf,您需要将WeakTypeTag 作为隐含在您的宏实现中,如下所示:

    def implValList[T](c: whitebox.Context)(implicit wt: c.WeakTypeTag[T]) ...
    

    其次,要创建文字,您使用这个构造而不是您的 quasiquote,(我相信它实际上什么都不做):

    Literal(Constant(m.name.toString))
    

    最后,我推荐使用这个守卫而不是isVal

    m.isCaseAccessor && m.isGetter
    

    正确检查案例类参数并且也是一个getter(案例类参数重复,一个为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")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-12
      • 1970-01-01
      • 2014-04-21
      • 2017-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多