我有一个json库,通过遵循Scala中的类型类模式来定义 ReadCodec
的概念(定义如何读取json)。此库使用无形'Typeclass
构造来免费为任何案例类派生 ReadCodec
的自动实例。
现在,我有一个代码生成器,在Scala中生成的类不是案例类(但可能应该是)。我可以让代码生成器为每个类生成ReadCodec实例,这就是我们现在所拥有的。但是现在如果我希望生成的类支持一些新的序列化形式,我需要修改代码生成以输出这个新类型类的实例。
有没有办法我可以修改代码生成器以输出具有 LabelledGeneric
实例的类或其他可以利用生成(通过宏)自动实例的机制的其他内容班?这样,生成的代码可以与使用Shapeless'Typeclass
实现实例的任何类型类模式互操作。
答案 0 :(得分:6)
有一个棘手的步骤,但您绝对可以定义自己的LabelledGeneric
实例。为了举例,我将使用Alex Archambault的argonaut-shapeless库,它不使用TypeClass
,但确实使用LabelledGeneric
,原理是相同的。
我们班的第一个:
class Foo(val i: Int, val s: String)
然后是我们的实例:
import shapeless._, labelled._, record._, syntax.singleton._
implicit object fooGeneric extends LabelledGeneric[Foo] {
val iw = Witness('i)
val sw = Witness('s)
type Repr = FieldType[iw.T, Int] :: FieldType[sw.T, String] :: HNil
def from(r: Repr): Foo = new Foo(r('i), r('s))
def to(t: Foo): Repr = ('i ->> t.i) :: ('s ->> t.s) :: HNil
}
请注意,我们需要一种方法来引用Repr
中记录键的单例类型,因此我们首先定义几个见证。这是棘手的部分。
现在你只需写下:
import argonaut._, Argonaut._, Shapeless._
然后:
scala> implicitly[EncodeJson[Foo]].encode(new Foo(42, "foo"))
res0: argonaut.Json = {"s":"foo","i":42}
如果您愿意,我可以将LabelledTypeClass
示例放在一起,但这个想法完全相同。