Создать сопутствующий объект для класса дела с помощью методов (field = method)
Создать сопутствующий объект для case-класса с помощью макросов scala
некоторый пример кода, который я пробовал, он работает, я могу получить список кортежей (имя -> тип), но как создать объект в той же области видимости?
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})
"""
)
Можно ли аннотировать некоторый класс дел и созданный компаньон сделать видимым в той же области видимости?
// test case: defined a class with some fields
@GenerateCompanionWithFields
case class SomeCaseClass(i: Int, b: Byte, c: Char)
Цель:
SomeCaseClass.i() // returns Int
SomeCaseClass.b() // returns Byte
SomeCaseClass.c() // returns Char
1 ответ
Ваш код, похоже, предназначен для макросов def. Но если вы хотите создать компаньон, вы должны использовать макро-аннотации
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"
// };
// ()
//}