通过这个有用的guide
学习无形我试图在this
中合并我从this exercice学到的知识结果是这段代码:
import shapeless._
object GenericV3 {
trait CsvEncoder[A] {
def width: Int
def encode(value: A): List[String]
}
def createEncoder[A](cols: Int)(func: A => List[String]): CsvEncoder[A] =
new CsvEncoder[A] {
val width = cols
def encode(value: A): List[String] =
func(value)
}
implicit val stringEncoder: CsvEncoder[String] =
createEncoder(1)(str => List(str))
implicit val intEncoder: CsvEncoder[Int] =
createEncoder(1)(num => List(num.toString))
implicit val booleanEncoder: CsvEncoder[Boolean] =
createEncoder(1)(bool => List(if(bool) "cone" else "glass"))
implicit val doubleEncoder: CsvEncoder[Double] =
createEncoder(1)(d => List(d.toString))
import shapeless.{HList, HNil, ::}
implicit val hnilEncoder: CsvEncoder[HNil] =
createEncoder(0)(hnil => Nil)
implicit def hlistEncoder[H, T <: HList](
implicit
hEncoder: Lazy[CsvEncoder[H]],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :: T] =
createEncoder(hEncoder.value.width + tEncoder.width) {
case h :: t =>
hEncoder.value.encode(h) ++ tEncoder.encode(t)
}
import shapeless.{Coproduct, CNil, :+:, Inl, Inr}
implicit val cnilEncoder: CsvEncoder[CNil] =
createEncoder(0) { cnil =>
throw new Exception("The impossible has happened!")
}
implicit def coproductEncoder[H, T <: Coproduct](
implicit
hEncoder: Lazy[CsvEncoder[H]],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :+: T] =
createEncoder(hEncoder.value.width + tEncoder.width) {
case Inl(h) => hEncoder.value.encode(h) ++ List.fill(tEncoder.width)("")
case Inr(t) => List.fill(hEncoder.value.width)("") ++ tEncoder.encode(t)
}
import shapeless.Generic
implicit def genericEncoder[A, R](
implicit
gen: Generic.Aux[A, R],
lEncoder: Lazy[CsvEncoder[R]]
): CsvEncoder[A] =
createEncoder(lEncoder.value.width) { value =>
lEncoder.value.encode(gen.to(value))
}
def writeCsv[A](values: List[A])(implicit encoder: CsvEncoder[A]): String =
values.map(encoder.encode).map(_.mkString(",")).mkString("\n")
}
使用密封的案例类调用GenericV3.writeCsv
时,案例类包含密封的案例类本身。
指南中的示例:
sealed trait Tree[A]
final case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
final case class Leaf[A](value: A) extends Tree[A]
我在运行时遇到了StackOverflowError。 例子
GenericV3.writeCsv[Tree[String]](List(Branch(Leaf("toto"),Leaf("titi"))))
产生错误是因为我在匹配Inl和Inr之前调用hEncoder.value.width
。
我试着看看它是如何在其他库中完成的。 我看到this看起来一样。
所以我想我错过了什么。
ps:我要感谢这位guide的作者非常有帮助