假设我在 Scala 中有一个 ADT:
sealed trait Base
case class Foo(i: Int) extends Base
case class Baz(x: String) extends Base
我想将此类型的值编码为如下所示的 JSON:
{ "Foo": { "i": 10000 }}
{ "Baz": { "x": "abc" }}
幸运的是,这正是编码 circe 的通用派生提供的!
scala> import io.circe.generic.auto._, io.circe.syntax._
import io.circe.generic.auto._
import io.circe.syntax._
scala> val foo: Base = Foo(10000)
foo: Base = Foo(10000)
scala> val baz: Base = Baz("abc")
baz: Base = Baz(abc)
scala> foo.asJson.noSpaces
res0: String = {"Foo":{"i":10000}}
scala> baz.asJson.noSpaces
res1: String = {"Baz":{"x":"abc"}}
问题在于,circe 使用的编码器取决于我们正在编码的表达式的静态类型。这意味着如果我们尝试直接解码其中一个案例类,我们会丢失判别器:
scala> Foo(10000).asJson.noSpaces
res2: String = {"i":10000}
scala> Baz("abc").asJson.noSpaces
res3: String = {"x":"abc"}
…但Base
即使静态类型为Foo
. 我知道我可以为所有案例类定义显式实例,但在某些情况下我可能有很多,我不想枚举它们。
(请注意,这是一个多次出现的问题——<a href="https://gitter.im/circe/circe?at=5bc72f4ec08b8b30672b396c" rel="noreferrer">例如这里。)