【问题标题】:merge `Tree` and `List[Tree]` in scala compile-time reflection在scala编译时反射中合并`Tree`和`List [Tree]`
【发布时间】:2018-07-16 07:10:48
【问题描述】:

我有一个 scala 宏,可以即时为类创建构造函数。
例如,如果我们有一个类case class PersonConfig(name: String, age: Int, isFemale: Boolean)。我有类名的树结构和传递给类的参数,如下所示

@ val className = q"PersonConfig"
className: Ident = Ident(PersonConfig)

@ val args = List(q""""Jyn Erso"""", q"26", q"true")
args: List[Literal] = List(Literal(Constant("Jyn Erso")), Literal(Constant(26)), Literal(Constant(true)))

现在要创建将创建 PersonConfig 实例的 AST 结构(即 PersonConfig("Jyn Erso", 26, true)),我必须将 className 和 args 值结合起来。这里的挑战是args 可以是任意大小,因为该宏可用于为许多不同的类构造构造函数。

目前明显但不那么 DRY 和冗长的解决方案是对 args 参数进行模式匹配并创建 AST 结构,如下所示。

import scala.reflect.runtime.universe
def makeExpr(className: universe.Tree, args: List[universe.Tree]): universe.Tree = {
  args.reverse match {
    case node1 :: Nil => q"$className($node1)"
    case arg1 :: arg2 :: Nil => q"$className($arg1, $arg2)"
    case arg1 :: arg2 :: arg3 :: Nil => q"$className($arg1, $arg2, $arg3)"
    case arg1 :: arg2 :: arg3 :: arg4 :: Nil => q"$className($arg1, $arg2, $arg3, $arg4)"
    case arg1 :: arg2 :: arg3 :: arg4 :: arg5 :: Nil => q"$className($arg1, $arg2, $arg3, $arg4, $arg5)"
    case Nil => throw new Exception(s"argument list for class ${className.toString} cannot be empty")
    case _ => throw new Exception(s"argument list for class ${className.toString} is too long")
  }

}

但是有没有更好的方法来有效地处理这个问题,哪个更干燥?例如使用 foldLeft 或其他等效方法来实现 makeExpr 函数的作用?

【问题讨论】:

    标签: scala scala-macros scala-reflect scala-quasiquotes


    【解决方案1】:

    我设法使用 foldLeft 完成了这项工作,如下所示。

      def makeExpr(c: blackbox.Context)(className: c.Tree, args: List[c.Tree]): c.universe.Tree = {
        import c.universe._
        args.reverse match {
          case head :: tail => tail.foldLeft(q"$className($head)")({
           case (q"$_(..$params)", node) => q"$className(..${params :+ node})"          })
          case Nil => throw new MacroException(s"argument list for class ${className.toString} cannot be empty")
        }
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-28
      • 2019-10-14
      • 2020-09-04
      • 2013-06-26
      • 1970-01-01
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      相关资源
      最近更新 更多