Scala基于shapeless实现case class转CSV时找不到Mapper隐式参数报错
问题根源
报错的核心原因是 csvMapper 中定义的Case匹配规则和LabelledGeneric生成的HList元素类型不兼容:LabelledGeneric 转换case class得到的HList每个元素类型是 FieldType[K, V],其中K是对应字段名的单例Symbol类型(比如对应project字段就是'project.type),而你之前的代码写死了标签类型为泛型的Symbol,导致Case无法匹配到实际的字段类型,自然就找不到Mapper实例。
修复方案
只需要修改CsvBuilder中csvMapper的caseEncode定义,给标签增加泛型参数即可:
import shapeless._ import shapeless.labelled.FieldType import shapeless.ops.hlist.Mapper import shapeless.ops.record.ToMap class CsvBuilder[Row](rows: List[Row]) { object csvMapper extends Poly1 { // 增加K <: Symbol泛型参数,匹配具体的字段名单例类型 implicit def caseEncode[K <: Symbol, V]( implicit e: CsvEncoder[V] ): Case.Aux[FieldType[K, V], FieldType[K, String]] = at[FieldType[K, V]](s => field[K](e.encode(s))) } def build[Repr <: HList, OutRepr <: HList]( implicit labelledGeneric: LabelledGeneric.Aux[Row, Repr], mapper: Mapper.Aux[csvMapper.type, Repr, OutRepr], toMap: ToMap.Aux[OutRepr, Symbol, String] ): List[Map[String, String]] = { def transform(row: Row): Map[String, String] = { val formattedRows = labelledGeneric .to(row) .map(csvMapper) val fields = toMap(formattedRows) .map { case (k: Symbol, value: String) => (k.name -> value) // 建议用k.name替代toString,避免输出带单引号的'project格式 } fields } rows.map(transform(_)) } }
额外优化点:把k.toString改成k.name可以直接得到字段名的原始字符串,避免toString输出带单引号前缀的格式。
修改完成后运行测试用例即可得到正常输出:
List(Map(project -> "", something -> "", site -> "", state -> ""))
内容的提问来源于stack exchange,提问作者Krzysztof Atłasik
相关产品推荐
相关产品推荐

