gpt4 book ai didi

scala - 如何使用 scala 宏创建函数对象(创建 Map[String, (T) => T])

转载 作者:行者123 更新时间:2023-12-01 12:45:16 26 4
gpt4 key购买 nike

我正在尝试使用 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 切换到 (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]

最佳答案

除了需要将 T 拼接到准引号之外,您的代码几乎所有内容都正确,即编写 $tpe 而不仅仅是 T

为了看起来更自然,我通常在宏中显式声明类型标签证据,例如def foo[T](c: Context)(隐式 T: c.WeakTypeTag[T]) = ...。之后我就写了 $T,它看起来几乎没问题:)

你可能会问,为什么quasiquotes不能直接在写的地方弄清楚T指的是宏的类型参数,然后自动拼接进去。那会很实际上,合理的问题。在像 Racket 和 Scheme 这样的语言中,准引号足够聪明,可以记住它们所写的词法上下文,但在 Scala 中,这有点困难,因为语言中有很多不同的范围。然而,有一个到达那里的计划,并且已经在朝着这个方向进行研究:https://groups.google.com/forum/#!topic/scala-language/7h27npd1DKI .

关于scala - 如何使用 scala 宏创建函数对象(创建 Map[String, (T) => T]),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20689852/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com