You need to enable JavaScript to run this app. Scala基于shapeless实现case class转CSV时找不到Mapper隐式参数报错
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 21:36:06