您的位置:首页 > 其它

scala macro annotation 使用 例子

2015-09-04 19:50 281 查看
功能:用 宏注解实现一个 为case class 生成get set 方法 注解

github 地址:https://github.com/1178615156/use-scala-macro-annotation-make-get-set

//功能如下

@MakeGetSet
case class Hello(
var a: String,
var int: Int,
var option: Option[String],
var none: Option[AnyRef] = None,
val hello: Boolean = true
)

object Main {
def main(args: Array[String]) {
val a = new Hello("a", 1, Some("option"))
//a.a
println(a.getA)//a

//a.int
println(a.getInt)//1

//return option.getOrElse(null)
println(a.getOption)//option

//return option.getOrElse(null)
println(a.getNone)//null

//a.none=Option(Some(""))
a.setNone(Some(""))
println(a.none)//Some(Some())

//a.none=Some("")
a.none = Some("")
println(a.none)//Some()

println(a.getHello)//true

//no have this method because hello is val
//a.setHello(false )
}
}


宏 的实现代码 :

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
import scala.annotation.{compileTimeOnly, StaticAnnotation}

/**
* Created by YuJieShui on 2015/9/4.
*/
@compileTimeOnly("")
class MakeGetSet extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro AnnotationGetSetMacroImpl.impl
}

class AnnotationGetSetMacroImpl(val c: Context) {

import c.universe._

//get case class
def getInCaseClass(list_annottees: List[Tree]) = list_annottees match {
case caseClass :: Nil => caseClass
case caseClass :: companionObject :: Nil => caseClass
}

def impl(annottees: c.Expr[Any]*): c.Expr[Any] = {
val inCaseClass = getInCaseClass(annottees.map(_.tree).toList)

val out: c.universe.Tree = inCaseClass match {
//if inCaseClass no a case class
//throw match error
case q"case class $name(..$params) extends ..$bases { ..$body }" =>

val list_params: List[ValDef] = params.asInstanceOf[List[ValDef]]

val get_set_params_func = list_params.map((param: c.universe.ValDef) => {
//get method name
val get_name = TermName("get" + {
val vn = param.name.toString;
vn.head.toString.toUpperCase() + vn.tail
})
//set method name
val set_name = TermName("set" + {
val vn = param.name.toString;
vn.head.toString.toUpperCase() + vn.tail
})

param match {
case ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) =>
val v_type: c.universe.Tree = tq"$tpt"

//如果参数类型为泛型参数
v_type.children.headOption.map {
// where type is Option[_]
case tq"Option" =>
Tuple2(
q"""@..${mods.annotations}
def $get_name = $name.orNull
""",
//where value is var
//make set method
if (mods.hasFlag(Flag.MUTABLE))
q"def $set_name(sss:${v_type.children(1)}):Unit=this.${name}=Option(sss)"
else
q""
)
//other such : Future[_],List[_]
case _ =>
Tuple2(
q"def $get_name = ${param.name}",
q""
)
} //非泛型参数
.getOrElse(Tuple2(
q"def $get_name= {${param.name}}",
if (mods.hasFlag(Flag.MUTABLE))
q"def $set_name(sss:$v_type):Unit=this.${name}=sss"
else
q""
))
}
}).flatMap(t2 => List(t2._1, t2._2))

q"""
case class $name(..$params) extends ..$bases {
..$get_set_params_func
..$body
}
"""
}
c.Expr(out)
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: