У меня есть макрос 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)))
Теперь, чтобы создать структуру AST, которая создала бы экземпляр PersonConfig
(т.е. PersonConfig("Jyn Erso", 26, true)) мне нужно будет объединить значения className и args. Проблема здесь в том, что args
может быть любого размера, поскольку этот макрос можно использовать для создания конструкторов для многих разных классов.
в настоящее время очевидным, но менее СУХИМ и подробным решением является сопоставление шаблона для параметра 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
?