您可以使用自动推导
import io.circe.generic.auto._
case class Person(name: String)
而不是半自动推导
io.circe.generic.semiauto
case class Person(name: String)
object Person {
implicit val fooDecoder: Person[Foo] = semiauto.deriveDecoder
implicit val fooEncoder: Person[Foo] = semiauto.deriveEncoder
}
或宏注解@JsonCodec简化半自动推导
import io.circe.generic.JsonCodec
@JsonCodec case class Person(name: String)
假设您更喜欢半自动推导而不是自动推导。
扩展特征是不正确的方式
class JSONGetter extends Getter[MyClass] with JsonDecoding[MyClass] {
// ...
}
问题是这deriveDecoder
是一个宏,在适当的位置扩展宏很重要。如果您扩展一个特征并将隐式放在那里,那么宏会在不正确的位置展开。
您可以定义自己的宏注释,将添加必要的隐式
@jsonDecoding
class JSONGetter extends Getter[MyClass]
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
@compileTimeOnly("enable macro paradise to expand macro annotations")
class jsonDecoding extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro jsonDecodingMacro.impl
}
object jsonDecodingMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
annottees match {
case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" :: tail =>
val tparamNames = tparams.map {
case q"$mods type $tpname[..$tparams] = $tpt" => tpname
}
q"""
$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self =>
..$stats
implicit val decoder: _root_.io.circe.Decoder[$tpname[..$tparamNames]] =
_root_.io.circe.derivation.deriveDecoder[$tpname[..$tparamNames]](_root_.io.circe.derivation.renaming.snakeCase)
}
..$tail
"""
// or should the implicit be added to companion object?
case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" =>
// ...
case q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }" =>
//...
}
}
}
斯卡拉 | 如何将此代码放入宏注释中?
如何在 Scala 2 中使用 Scala 宏减少样板代码?
通过多个对象传递隐式参数
Scala 基于宏的注解重用
同样,对于Cats类型类,您可以使用Kittens以原子方式派生类型类
import cats.derived.auto.functor._
case class Cat[Food](food: Food, foods: List[Food])
或半自动
import cats.derived.semiauto
case class Cat[Food](food: Food, foods: List[Food])
object Cat {
implicit val fc: Functor[Cat] = semiauto.functor
}
如果您更喜欢半自动派生,那么您可以使用Katnip宏注释而不是semiauto.functor
为每个类编写必要的隐式
import io.scalaland.catnip.Semi
@Semi(Functor) case class Cat[Food](food: Food, foods: List[Food])