编译错误是
could not find implicit value for parameter S: Show[Product with Animal with java.io.Serializable]
你可以让Animal扩展Product和Serializable
sealed trait Animal extends Product with Serializable
https://typelevel.org/blog/2018/05/09/product-with-serializable.html
也不是手动定义隐式Show[Animal]
implicit val showAnimal: Show[Animal] = {
case x: Cat => implicitly[Show[Cat]].show(x)
case x: Dog => implicitly[Show[Dog]].show(x)
// ...
}
您可以使用macros 为密封特征(具有后代实例)派生Show
def derive[A]: Show[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val typA = weakTypeOf[A]
val subclasses = typA.typeSymbol.asClass.knownDirectSubclasses
val cases = subclasses.map{ subclass =>
cq"x: $subclass => _root_.scala.Predef.implicitly[Show[$subclass]].show(x)"
}
q"""
new Show[$typA] {
def show(a: $typA): _root_.java.lang.String = a match {
case ..$cases
}
}"""
}
implicit val showAnimal: Show[Animal] = derive[Animal]
或Shapeless
implicit val showCnil: Show[CNil] = _.impossible
implicit def showCcons[H, T <: Coproduct](implicit
hShow: Show[H],
tShow: Show[T]
): Show[H :+: T] = _.eliminate(hShow.show, tShow.show)
implicit def showGen[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
show: Show[C]
): Show[A] = a => show.show(gen.to(a))
或Magnolia
object ShowDerivation {
type Typeclass[T] = Show[T]
def combine[T](ctx: CaseClass[Show, T]): Show[T] = null
def dispatch[T](ctx: SealedTrait[Show, T]): Show[T] =
value => ctx.dispatch(value) { sub =>
sub.typeclass.show(sub.cast(value))
}
implicit def gen[T]: Show[T] = macro Magnolia.gen[T]
}
import ShowDerivation.gen
或Scalaz-deriving
@scalaz.annotation.deriving(Show)
sealed trait Animal extends Product with Serializable
object Show {
implicit val showDeriving: Deriving[Show] = new Decidablez[Show] {
override def dividez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Prod[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = null
override def choosez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Cop[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = z => {
val x = g(z).zip(tcs)
x.b.value.show(x.a)
}
}
}
对于cats.Show 和Kittens,您可以只写
implicit val showAnimal: Show[Animal] = cats.derived.semi.show
问题是List(garfield, odie) 中的garfield 和odie 具有相同的类型,并且是Animal 而不是Cat 和Dog。如果您不想为父类型定义类型类的实例,您可以使用类似列表的结构来保留单个元素的类型,HListgarfield :: odie :: HNil。
用于比较 Dotty 中的派生类型类
How to access parameter list of case class in a dotty macro