【发布时间】:2014-01-20 22:23:49
【问题描述】:
我想使用宏来生成案例类的设置器。例如:
case class Person(name: String, age: Int)
Macro.mkSetter[Person, String]("name") : Person => String => Person
我尝试了以下实现,但我不断得到以下结果
error: scala: Error: Unknown source file: embeddedFile--QuasiquoteCompat.scala@6....
(我正在使用带有宏天堂 2.0.0-SNAPSHOT 的 scala 2.10.3)
object Macro {
def mkSetter[A, B](fieldName: String): (A,B) => A = macro mkSetter_impl[A,B]
def mkSetter_impl[A: c.WeakTypeTag, B: c.WeakTypeTag](c : Context)(fieldName: c.Expr[String]): c.Expr[(A,B) => A] = {
import c.universe._
val (aTpe, bTpe) = (weakTypeOf[A], weakTypeOf[B])
val constructor = aTpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.getOrElse(c.abort(c.enclosingPosition, s"Cannot find constructor in ${weakTypeOf[A]}"))
val field = constructor.paramss.head.find(
_.name.decoded == fieldName.toString()
).getOrElse(c.abort(c.enclosingPosition, s"Cannot find constructor field named in $fieldName"))
c.Expr[(A,B) => A](q"{(a: $aTpe, b: $bTpe) => a.copy(${field.name} = b)}")
}
}
我确实意识到_.name.decoded == fieldName.toString() 不是检查方法名称的正确方法(即使_.name.decoded == "name" 似乎没问题)
加分项: 使用可变参数对具有相同类型的参数进行泛化宏,例如
def mkSetter[A, B](fieldNames: String*): A => B => B ... => A = macro mkSetter_impl[A,B]
谢谢!
【问题讨论】:
-
您能否提供有关您的环境的更多详细信息,例如在 github 上发布一个项目?您面临的问题似乎与您尝试编写的宏无关。只需进行几个小改动,我就能够成功运行它。
-
谢谢@EugeneBurmako。这是我正在处理的project。
-
sbt compile和sbt test都可以。我需要做一些特别的事情来重现这个问题吗? -
我添加了一些 macro tests 与 sbt 一起传递。但是,当我尝试运行相同的测试时,我遇到了与以前使用 intellij(社区版 v 13.0.1)相同的错误。
标签: scala scala-macros