2014-01-20 23 views
0

我想使用宏來爲case類生成setter。例如:Scala宏:如何創建案例類的setter函數

case class Person(name: String, age: Int) 

Macro.mkSetter[Person, String]("name") : Person => String => Person 

我嘗試了以下實現,但我不斷收到以下

error: scala: Error: Unknown source file: [email protected]

(我使用2.9.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

您能否提供有關您的環境的更多詳細信息,例如在github發佈項目?你面臨的問題似乎與你正在編寫的宏無關。只需稍作修改,我就能夠成功運行它。 –

+0

謝謝@EugeneBurmako。這是我正在研究的[項目](https://github.com/julien-truffaut/Lens/blob/macro/macros/src/main/scala/lens/Macro.scala)。 –

+0

'sbt compile'和'sbt test'都可以。我需要做一些特別的事情來重現這個問題嗎? –

回答