Как использовать макросы scala для создания функционального объекта (для создания Map [String, (T) => T])
Я пытаюсь использовать макросы Scala для создания карты классов случаев с одним параметромcopy
методы, каждый из которых принимает Play JsonJsValue
и экземпляр класса case, и возвращающий обновленную копию экземпляра. Однако у меня возникают проблемы с синтаксисом макроса для возврата объекта функции.
Учитывая класс случая
case class Clazz(id: Int, str: String, strOpt: Option[String])
намерение состоит в том, чтобы создать карту методов копирования класса
implicit def jsonToInt(json: JsValue) = json.as[Int]
implicit def jsonToStr(json: JsValue) = json.as[String]
implicit def jsonToStrOpt(json: JsValue) = json.asOpt[String]
Map("id" -> (json: JsValue, clazz: Clazz) = clazz.copy(id = json),
"str" -> (json: JsValue, clazz: Clazz) = clazz.copy(str = json), ...)
Я нашел два связанных вопроса:
Использование макросов для создания карты поля класса дела:Макросы Scala: создание карты из полей класса в Scala
Доступ к методу копирования класса case с помощью макроса:Как моделировать именованные параметры в вызовах методов с помощью макросов Scala?
... но я застрял в том, как я могу создать функциональный объект, чтобы я мог вернутьMap[String, (JsValue, T) => T]
Редактировать: Благодаря предложению Юджина Бурмако использовать квазицитаты - это то, где я сейчас использую Scala 2.11.0-M7, основывая свой код наПост Джонатана Чоу (Я переключился с использования (T, JsValue) => T на (T, String) => T, чтобы упростить импорт REPL)
Edit2: теперь включает сплайсинг $ tpe
import scala.language.experimental.macros
implicit def strToInt(str: String) = str.toInt
def copyMapImpl[T: c.WeakTypeTag](c: scala.reflect.macros.Context):
c.Expr[Map[String, (T, String) => T]] = {
import c.universe._
val tpe = weakTypeOf[T]
val fields = tpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.get.paramss.head
val methods = fields.map { field => {
val name = field.name
val decoded = name.decoded
q"{$decoded -> {(t: $tpe, str: String) => t.copy($name = str)}}"
}}
c.Expr[Map[Sring, (T, String) => T]] {
q"Map(..$methods)"
}
}
def copyMap[T]: Map[String, (T, String) => T] = macro copyMapImpl[T]
case class Clazz(i: Int, s: String)
copyMap[Clazz]