Generate companion object for case class with methods (field = method)

二次信任 提交于 2020-01-15 11:46:06

问题


Generate companion object for case class with scala-macros

some code example that i tried, it works i can get list of tuple (name -> type) but how to generate the object in the same scope?

  import c.universe._
  val tpe = weakTypeOf[T]

  val fields = tpe.decls.collectFirst {
    case m: MethodSymbol if m.isPrimaryConstructor => m
  } .get
    .paramLists
    .head

  val extractParams = fields.map { field =>
    val name = field.asTerm.name
    val fieldName = name.decodedName.toString
    val NullaryMethodType(fieldType) = tpe.decl(name).typeSignature

    c.Expr[List[(String, String)]](
      q"""
       ($fieldName, ${fieldType.toString})
      """
    )

Is it possible to annotate some case class and the generated companion make visible in the same scope?

// test case: defined a class with some fields
@GenerateCompanionWithFields
case class SomeCaseClass(i: Int, b: Byte, c: Char)

goal:

SomeCaseClass.i() // returns Int 
SomeCaseClass.b() // returns Byte
SomeCaseClass.c() // returns Char

回答1:


Your code seems to be intended for def macros. But if you want to generate companion you should use macro annotations

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

object Macros {
  @compileTimeOnly("enable macro paradise")
  class GenerateCompanionWithFields extends StaticAnnotation {
    def macroTransform(annottees: Any*): Any = macro Macro.impl
  }

  object Macro {
    def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
      import c.universe._
      annottees match {
        case (cls @ q"$_ class $tpname[..$_] $_(...$paramss) extends { ..$_ } with ..$_ { $_ => ..$_ }") :: Nil =>

          val newMethods = paramss.flatten.map {
            case q"$_ val $tname: $tpt = $_" =>
              q"def $tname(): String = ${tpt.toString}"
          }

          q"""
             $cls

             object ${tpname.toTermName} {
               ..$newMethods
             }
           """
      }
    }
  }
}

import Macros._

object App {
  @GenerateCompanionWithFields
  case class SomeCaseClass(i: Int, b: Byte, c: Char)
}

//Warning:scalac: {
//  case class SomeCaseClass extends scala.Product with scala.Serializable {
//    <caseaccessor> <paramaccessor> val i: Int = _;
//    <caseaccessor> <paramaccessor> val b: Byte = _;
//    <caseaccessor> <paramaccessor> val c: Char = _;
//    def <init>(i: Int, b: Byte, c: Char) = {
//      super.<init>();
//      ()
//    }
//  };
//  object SomeCaseClass extends scala.AnyRef {
//    def <init>() = {
//      super.<init>();
//      ()
//    };
//    def i(): String = "Int";
//    def b(): String = "Byte";
//    def c(): String = "Char"
//  };
//  ()
//}

automatically generate case object for case class



来源:https://stackoverflow.com/questions/57740226/generate-companion-object-for-case-class-with-methods-field-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!