Как исправить проблему "не удалось найти неявное значение для параметра свидетельства типа" при использовании магнолии

Я пытаюсь создать парсер CSV (с заголовками), который извлекает строку в case class. Я хочу, чтобы при извлечении учитывался заголовок (вместо того, чтобы полагаться наcase classпараметры находятся в том же порядке, что и в CSV) значения в полях справа. Я использую магнолию для десериализации. Чтобы проверить магнолию, я кормлю десериализаторMap содержащий содержимое CSV.

Я так называю декодер:

case class PlayerData(btag: String, team: String, status: String, role: String)
val csv = new CSV(Array(Map(
          ("btag" -> "btag#value"),
          ("team" -> "team_name"),
          ("status" -> "player_status"),
          ("role" -> "player role"),
        )))
val ps = csv.extract[PlayerData]
for(PlayerData(b, t, _, r) <- ps) {
  println(s"btag: $b, team: $t, role: $r")
}

Реализация декодера следующая:

object Decoding {
  object LineDecoder {
    implicit class DecoderOps[A: LineDecoder](p: Map[String, String]) {
      def decode: A = implicitly[LineDecoder[A]].decode(p)
    }

    type Typeclass[T] = LineDecoder[T]

    def combine[T](caseClass: CaseClass[LineDecoder, T]): LineDecoder[T] = new LineDecoder[T] {
      def cols: Int = caseClass.parameters.map(_.typeclass.cols).sum

      def decode(p: Map[String, String]): T = {

        @annotation.tailrec
        def make_param_list(row: Map[String, String],
                            cc_params: Seq[Param[Typeclass, T]],
                            c_params: Vector[Any]): T = {
          if(cc_params.isEmpty) {
            caseClass.rawConstruct(c_params)
          } else {
            val ctor_param = cc_params.head
            val tail = cc_params.tail
            val param_value = row.get(ctor_param.label).get
            make_param_list(row, tail, c_params :+ param_value)
          }
        }
        make_param_list(p, caseClass.parameters, Vector())
      }
    }
    def apply[T](fn: Map[String, String] => T, len: Int = 1) = new LineDecoder[T] {
      def decode(p: Map[String, String]): T = fn(p)
      def cols: Int = len
    }
    implicit def gen[T]: LineDecoder[T] = macro Magnolia.gen[T]
  }

  trait LineDecoder[T] {
    def cols: Int

    def decode(p: Map[String, String]): T
  }
}
class CSV(csv: Array[Map[String, String]]) {
  import Decoding._
  def extract[T: LineDecoder](): ArraySeq[T] = csv.map( line => {
                                                         implicitly[LineDecoder[T]].decode(line)
                                                       } )
}

Он был сильно вдохновлен цезурой.

При компиляции у меня такая ошибка:

[error] dev/scala/team-stats/src/main/scala/test.scala:67:25: could not find implicit value for evidence parameter of type Decoding.LineDecoder[CLI.PlayerData]
[error]     val ps = csv.extract[PlayerData]

Что я делаю неправильно?

1 ответ

Решение

Ставить

implicit val strLineDecoder: LineDecoder[String] = ??? // your implementation

к объекту-компаньону LineDecoder.

Магнолия может наследовать экземпляры класса типа для классов case и запечатанных черт, но не может угадать их для других типов.

Также def extract[T: LineDecoder : ClassTag](): Array[T] = ... должно быть вместо def extract[T: LineDecoder](): ArraySeq[T] = ....

Другие вопросы по тегам