我试图编写一个宏,将一个案例类的给定实例扩展为字符串表示。例如。 case class Foo(a: Int); Foo(1)
将成为a -> 1
。
所以我写了一个类型类来给我一个名为LabelledGeneric
的无形FieldList
字段名称。我将LabelledGeneric和FieldList实例传递给我的宏,我可以轻松地使宏生成所有字段的列表。但是,我不确定如何使用表示字段的字符串从我的宏体中的对象访问该字段。这是宏代码:
import FieldList._
import shapeless.{HList, LabelledGeneric}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Foo {
def foo_impl[T, L <: HList](c: blackbox.Context)
(t: c.Expr[T])
(gen: c.Expr[LabelledGeneric.Aux[T, L]],
fl: c.Expr[FieldList[L]]): c.Expr[String] = {
import c.universe._
reify {
val sb = new StringBuilder
val obj = t.splice
val generic = gen.splice
val fieldList = fl.splice
// T.fieldList returns a List[String] of the class' fields.
obj.fieldList(generic, fieldList).foldLeft(sb) { case (builder, next) =>
builder.append(next)
builder.append(" -> ")
builder.append() // How to get the value of obj.$next?
}.toString()
}
}
def foo[T, L <: HList](t: T)(implicit gen: LabelledGeneric.Aux[T, L], fl: FieldList[L]): String = macro foo_impl[T, L]
}
我不知道该怎么做的一行是我评论的第三行。
我确定我想要做的事情是无形的,但我正在尝试学习宏。我查看了quasiquotes,看起来他们可以支持这种行为,但看起来我必须在reify和quasiquotes和AFAICT之间做出选择我只能在reify块中访问Expr
的值(所以quasiquotes不会工作?)。
答案 0 :(得分:1)
使用quasiquotes完全可以拼接。只有你拼接Tree
,而不是Expr
(你可以Expr
到Tree
expr.tree
。这是一个对代码进行最小更改的解决方案:
import FieldList._
import shapeless.{HList, LabelledGeneric}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Foo {
def foo_impl[T, L <: HList](c: blackbox.Context)
(t: c.Tree)
(gen: c.Tree,
fl: c.Tree): c.Tree = {
import c.universe._
val q"$_(..$args)" = t
q"""
val sb = new _root_.scala.StringBuilder
val obj = $t
val generic = $gen
val fieldList = $fl
val argsList = _root_.scala.List(..$args)
// T.fieldList returns a List[String] of the class' fields.
obj.fieldList(generic, fieldList)
.zip(argsList)
.foldLeft(sb) { case (builder, (next, value)) =>
builder.append(next)
builder.append(" -> ")
builder.append(value)
}.toString()
"""
}
def foo[T, L <: HList](t: T)(implicit gen: LabelledGeneric.Aux[T, L], fl: FieldList[L]): String = macro foo_impl[T, L]
}
请注意我没有编译或测试过这个,因为我没有其他代码依赖于此。如果这确实有效,它可能不适用于更复杂的情况,如foo(Foo(b = "bar", a = 1))
。但是它可能会让你对如何使用quasiquotes有一个大概的了解。