找不到参数映射器的隐式值

Posted

技术标签:

【中文标题】找不到参数映射器的隐式值【英文标题】:Could not find implicit value for parameter Mapper 【发布时间】:2021-08-29 17:05:10 【问题描述】:

我尝试创建一个简单的基于无形函数来将案例类转换为字符串列表,然后我可以将其编码为 csv。

这里的重点是在case类的每个成员上调用类型类CsvEncoder,然后调用方法encode将其更改为字符串。

类型类:

trait CsvEncoder[T] 
  def encode(t: T): String


trait LowPriorityEncoder 
  implicit def genericEncoder[T]: CsvEncoder[T] = _.toString


object CsvEncoder extends LowPriorityEncoder 

  implicit def optionEncoder[T](
      implicit e: CsvEncoder[T]
  ): CsvEncoder[Option[T]] = _.fold("")(e.encode)


无形:

class CsvBuilder[Row](rows: List[Row]) 

  object csvMapper extends Poly1 

    implicit def caseEncode[V](
        implicit e: CsvEncoder[V]
    ): Case.Aux[FieldType[Symbol, V], FieldType[Symbol, String]] =
      at[FieldType[Symbol, V]](s => field[Symbol](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.toString -> value)
        

      fields
    

    rows.map(transform(_))

  

当我尝试使用简单的案例类时:

final case class ProjectCsvRow(
    project: Option[String],
    something: Option[String],
    site: Option[String],
    state: Option[Int]
)

new CsvBuilder[ProjectCsvRow](
  List(ProjectCsvRow(Some(""), None, None, None))
).build

我来了

找不到参数映射器的隐含值:shapeless.ops.hlist.Mapper.Aux[stabilizer$1.csvMapper.type,Repr,OutRepr]

我想我错过了什么,但我无法真正弄清楚。

我已经检查了每个字段是否有 CsvEncoder 的实例。

【问题讨论】:

当我做与此非常相似的事情时,我发现忘记所有花哨的东西(如Poly)并编写一个经典的头尾解码器要容易得多。如果您觉得有帮助,我可以用这种方法添加答案?或者,也许您已经尝试过了,但由于某种原因没有奏效? 这就是我最终所做的。感谢您的提示。 【参考方案1】:

首先,您的Poly 不正确。 Symbol 类型太粗糙。记录的键不仅仅是Symbols,它们是Symbol 的单例子类型。你应该定义

object csvMapper extends Poly1 
  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)))

其次,将Poly 嵌套到类(而不是对象)中可能很危险(它开始依赖于CsvBuilder 的实例,因此依赖于Row 类型)。所以把csvMapper移到CsvBuilder外面(这样它的路径就稳定了)。

【讨论】:

谢谢,我重构了我的解决方案以使用类型类派生,但很高兴知道我做错了什么。

以上是关于找不到参数映射器的隐式值的主要内容,如果未能解决你的问题,请参考以下文章

找不到参数 e 的隐式值

Scala 类型参数化,Shapeless - 找不到参数 Generic 的隐式值

找不到参数的隐式值

找不到参数 flash 的隐式值

找不到参数 enc 的隐式值:CsvEncoder[Shape]

akka-http:找不到参数解组的隐式值