生成创建 class 的应用方法
Generate apply methods creating a class
斯卡拉 2.13
我有很多类似的特征
trait SomeTrait[F[_]]{
def someOp(): F[Unit]
//...
}
及其实现
class SomeTraitImpl[F[_]: Sync] extends SomeTrait[F]{
//...
}
object SomeTrait{
def apply[F[_]: Sync](): SomeTrait[F] = new SomeTraitImpl[F]()
}
问题是这种带有单一应用方法的伴侣看起来很丑陋,而且它是一个样板。有没有办法自动生成 object
? simulacrum 或其他任何东西(手写的宏注释?)都可以做到吗?
您可以使用macro annotation
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
@compileTimeOnly("enable macro paradise")
class implApply extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro ImplApplyMacro.macroTransformImpl
}
object ImplApplyMacro {
def macroTransformImpl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
def applyMethod(tparams: Seq[Tree], tpname: TypeName): Tree = {
def tparamNames = tparams.map {
case q"$_ type $tpname[..$_] = $_" => tq"$tpname"
}
q"""def apply[..$tparams]()(implicit sync: Sync[${tparamNames.head}]): $tpname[..$tparamNames] =
new ${TypeName(tpname + "Impl")}[..$tparamNames]()"""
}
annottees match {
case (trt@q"$_ trait $tpname[..$tparams] extends { ..$_ } with ..$_ { $_ => ..$_ }") ::
q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil =>
q"""
$trt
$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
${applyMethod(tparams, tpname)}
..$body
}
"""
case (trt@q"$_ trait $tpname[..$tparams] extends { ..$_ } with ..$_ { $_ => ..$_ }") :: Nil =>
q"""
$trt
object ${tpname.toTermName} {
${applyMethod(tparams, tpname)}
}
"""
}
}
}
用法:
@implApply
trait SomeTrait[F[_]]{
def someOp(): F[Unit]
}
class SomeTraitImpl[F[_]: Sync] extends SomeTrait[F]{
override def someOp(): F[Unit] = ???
}
//Warning:scalac: {
// object SomeTrait extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// def apply[F[_]]()(implicit sync: Sync[F]): SomeTrait[F] = new SomeTraitImpl[F]()
// };
// ()
//}
斯卡拉 2.13
我有很多类似的特征
trait SomeTrait[F[_]]{
def someOp(): F[Unit]
//...
}
及其实现
class SomeTraitImpl[F[_]: Sync] extends SomeTrait[F]{
//...
}
object SomeTrait{
def apply[F[_]: Sync](): SomeTrait[F] = new SomeTraitImpl[F]()
}
问题是这种带有单一应用方法的伴侣看起来很丑陋,而且它是一个样板。有没有办法自动生成 object
? simulacrum 或其他任何东西(手写的宏注释?)都可以做到吗?
您可以使用macro annotation
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
@compileTimeOnly("enable macro paradise")
class implApply extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro ImplApplyMacro.macroTransformImpl
}
object ImplApplyMacro {
def macroTransformImpl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
def applyMethod(tparams: Seq[Tree], tpname: TypeName): Tree = {
def tparamNames = tparams.map {
case q"$_ type $tpname[..$_] = $_" => tq"$tpname"
}
q"""def apply[..$tparams]()(implicit sync: Sync[${tparamNames.head}]): $tpname[..$tparamNames] =
new ${TypeName(tpname + "Impl")}[..$tparamNames]()"""
}
annottees match {
case (trt@q"$_ trait $tpname[..$tparams] extends { ..$_ } with ..$_ { $_ => ..$_ }") ::
q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil =>
q"""
$trt
$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
${applyMethod(tparams, tpname)}
..$body
}
"""
case (trt@q"$_ trait $tpname[..$tparams] extends { ..$_ } with ..$_ { $_ => ..$_ }") :: Nil =>
q"""
$trt
object ${tpname.toTermName} {
${applyMethod(tparams, tpname)}
}
"""
}
}
}
用法:
@implApply
trait SomeTrait[F[_]]{
def someOp(): F[Unit]
}
class SomeTraitImpl[F[_]: Sync] extends SomeTrait[F]{
override def someOp(): F[Unit] = ???
}
//Warning:scalac: {
// object SomeTrait extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// def apply[F[_]]()(implicit sync: Sync[F]): SomeTrait[F] = new SomeTraitImpl[F]()
// };
// ()
//}