【发布时间】:2013-12-19 19:13:53
【问题描述】:
我正在尝试使用 Scala 宏来创建单参数 copy 方法的案例类映射,每个方法都接受 Play Json JsValue 和案例类实例,并返回实例的更新副本。但是,我遇到了返回函数对象的宏语法问题。
给定一个案例类
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 Macros: Making a Map out of fields of a class in Scala
使用宏访问案例类复制方法:Howto model named parameters in method invocations with Scala macros?
...但我不知道如何创建一个函数对象,以便我可以返回一个Map[String, (JsValue, T) => T]
编辑:感谢 Eugene Burmako 建议使用准引号 - 这是我目前使用 Scala 2.11.0-M7 的地方,我的代码基于 Jonathan Chow's post(我从使用 (T, JsValue) => T to (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]
【问题讨论】:
-
我想知道是否有更简单的方法可以在不使用宏的情况下完成您想要完成的工作。您是否试图从本质上获取
JsValue并将其附加到Clazz的现有实例?即(概念上):Json.obj("id" -> newId) ++ instance应该等于instance.copy(id = newId) -
@ggreiner 是的,当前代码从数据库中检索
Clazz实例(MySql 之上的 Slick),将其分解为 json,更新 json,将其转换回更新后的Clazz实例,并使用新实例更新数据库。我们探索宏作为创建Map[String, CopyFun]的一种方式的原因是我们希望将 json 处理与数据库层分离 -
你考虑过使用准引号吗?
-
@EugeneBurmako - 感谢您的建议,我已经更新了我的问题 - 假设我已经正确编写了宏,我无法确定调用它的语法
标签: scala reflection macros case-class scala-macros