【问题标题】:Generate apply methods creating a class生成创建类的应用方法
【发布时间】:2020-09-08 23:47:27
【问题描述】:

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

问题是这样的单一应用方法看起来很丑陋,而且它是一个样板。有没有办法自动生成object? simulacrum 或其他任何东西(手写的宏注释?)可以做到吗?

【问题讨论】:

  • 您是否研究过案例类/案例对象?他们为你生成了很多样板文件。
  • @JamesWhiteley 问题是我需要从 apply 方法返回确切的 SomeTrait。不是SomeTraitImpl。这是主要区别。

标签: scala functional-programming scala-cats scala-macros companion-object


【解决方案1】:

您可以使用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]()
//  };
//  ()
//}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-09
    • 2022-08-06
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 2018-04-17
    • 1970-01-01
    • 2022-06-25
    相关资源
    最近更新 更多