生成类的应用方法

问题描述 投票:0回答:1

Scala 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]()
}

问题是,与这种apply方法一起使用的情况看起来很难看,这是一个样板。有没有一种方法可以自动生成object? Simulacrum或其他任何东西(手写的宏注释吗?)可以做到吗?

scala functional-programming scala-cats companion-object
1个回答
0
投票

您可以使用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._

    annottees match {
      case q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }" ::
        q"$mods1 object $tname extends { ..$earlydefns1 } with ..$parents1 { $self1 => ..$body }" :: Nil =>
        val tparams1 = tparams.map {
          case q"$mods type $tpname[..$tparams] = $tpt" => tq"$tpname"
        }
        q"""
           $mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }
           $mods1 object $tname extends { ..$earlydefns1 } with ..$parents1 { $self1 =>
             def apply[..$tparams]()(implicit sync: Sync[${tparams1.head}]): $tpname[..$tparams1] = new ${TypeName(tpname + "Impl")}[..$tparams1]()
             ..$body
           }
        """
    }
  }
}

@implApply
trait SomeTrait[F[_]]{
  def someOp(): F[Unit]
}

class SomeTraitImpl[F[_]: Sync] extends SomeTrait[F]{
  override def someOp(): F[Unit] = ???
}

object SomeTrait

//Warning:scalac: {
//  object SomeTrait extends scala.AnyRef {
//    def <init>() = {
//      super.<init>();
//      ()
//    };
//    def apply[F[_]]()(implicit sync: Sync[F]): SomeTrait[F] = new SomeTraitImpl[F]()
//  };
//  ()
//}

此注释期望伴随对象存在,并向其中添加apply。如果伴侣对象不存在,那么在这种情况下应创建它,然后应对此宏注释进行一些修改:

automatically generate case object for case class

© www.soinside.com 2019 - 2024. All rights reserved.