Cómo usar macros de Scala para crear un objeto de función (para crear un Mapa [Cadena, (T) => T])
Estoy intentando usar macros de Scala para crear un mapa de clase de caso de un solo parámetrocopy
métodos, con cada método aceptando un Play JsonJsValue
y una instancia de clase de caso, y devolver una copia actualizada de la instancia. Sin embargo, estoy teniendo problemas con la sintaxis de la macro para devolver un objeto de función.
Dado una clase de caso
case class Clazz(id: Int, str: String, strOpt: Option[String])
La intención es crear un mapa de los métodos de copia de la clase.
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), ...)
He encontrado dos preguntas relacionadas:
Usando macros para crear un mapa de campo de clase de caso:Macros de Scala: hacer un mapa de los campos de una clase en Scala
Accediendo al método de copia de clase de caso usando una macro:¿Cómo modelar parámetros nombrados en invocaciones de métodos con macros de Scala?
... pero estoy atascado en cómo puedo crear un objeto de función para que pueda devolver unMap[String, (JsValue, T) => T]
Edit: Gracias a la sugerencia de Eugene Burmako de usar cuasicotas, aquí es donde actualmente estoy usando Scala 2.11.0-M7, basando mi código enLa publicación de jonathan chow (Cambié de usar (T, JsValue) => T a (T, String) => T para simplificar mis importaciones de REPL)
Edit2: Ahora incorporando $ tpe empalme
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]