Scala宏:如何为案例类创建setter函数

时间:2014-01-20 22:23:50

标签: scala scala-macros

我想使用宏为case类生成一个setter。 e.g:

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....

(我正在使用scala 2.10.3和宏天堂2.0.0-SNAPSHOT)

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"似乎没问题)

奖励点:使用相同类型参数的varags参数来概括宏,例如

 def mkSetter[A, B](fieldNames: String*): A => B => B ... => A = macro mkSetter_impl[A,B]

谢谢!

1 个答案:

答案 0 :(得分:1)

似乎是由https://github.com/scalamacros/paradise/issues/11引起的。本周我计划解决这个问题,所以很快就会好起来的。您可以在scalamacros.org(http://scalamacros.org/news/rss.xml)订阅更新,或者在Twitter上关注我,以便在部署修补程序时收到通知。