Переменная длина "выберите" с квази-кавычками
С помощью квазицитат Scala вы можете легко создавать деревья выбора, например:
> tq"a.b.MyObj"
res: Select(Select(Ident(TermName("a")), TermName("b")), TermName("MyObj"))
Мой вопрос: как мне это сделать, если список вещей, из которых можно выбрать (a,b,... и т. Д.), Имеет переменную длину (и, следовательно, в переменной, в которую необходимо вставить)?
Я надеялся, что подъем будет работать (например, tq"""..${List("a","b","MyObj")}"""
но это не так. Или, может быть, даже это tq"""${List("a","b","MyObj").mkString(".")}"""
, но не повезло.
Есть ли способ поддержать это с помощью квазицитат? Или мне просто нужно построить дерево выбора вручную в этом случае?
1 ответ
Я не думаю, что есть способ сделать это напрямую с помощью квазицитат. Я определенно уверен, что что-нибудь вроде tq"""${List("a","b","MyObj").mkString(".")}"""
не будет работать. Я понимаю квазицитаты, что они просто сахар для экстракторов и применяются.
Однако, основываясь на этой идее, мы можем определить собственный экстрактор, который будет делать то, что вы хотите. (Кстати, я уверен, что есть более хороший способ выразить это, но вы поняли...)
object SelectTermList {
def apply(arg0: String, args: List[String]): universe.Tree =
args.foldLeft(Ident(TermName(arg0)).asInstanceOf[universe.Tree])
((s,arg) => Select(s, TermName(arg)))
def unapply(t: universe.Tree): Option[(String,List[String])] = t match {
case Ident(TermName(arg0)) => Some((arg0, List()))
case Select(SelectTermList(arg0,args),TermName(arg)) =>
Some((arg0, args ++ List(arg)))
case _ => None
}
}
Затем вы можете использовать это как для конструирования, так и для извлечения выражений вида a.b.MyObj
,
Экстрактор тесты:
scala> val SelectTermList(obj0,selectors0) = q"a.b.c.d.e.f.g.h"
obj0: String = a
selectors0: List[String] = List(b, c, d, e, f, g, h)
scala> val q"someObject.method(${SelectTermList(obj1,selectors1)})" = q"someObject.method(a.b.MyObj)"
obj1: String = a
selectors1: List[String] = List(b, MyObj)
Соответствующие прикладные тесты:
scala> SelectTermList(obj0,selectors0)
res: universe.Tree = a.b.c.d.e.f.g.h
scala> q"someObject.method(${SelectTermList(obj1,selectors1)})"
res: universe.Tree = someObject.method(a.b.MyObj)
Как видите, нет проблем с вложением экстракторов глубоко в квази-кавычки, как при построении, так и при извлечении.