0

我正在尝试制作一个 CSV(带标题)解析器,将一行提取到case class. 我希望提取依赖于标题来影响(而不是依赖于case class与 CSV 中的参数顺序相同)正确字段的值。我正在使用magnolia进行反序列化部分。为了测试magnolia,我提供了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)
                                                       } )
}

它深受caesura的启发。

编译时,我有这个错误:

[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]

我究竟做错了什么?

4

1 回答 1

1

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

到 的伴生对象LineDecoder

Magnolia 可以为案例类和密封特征派生类型类的实例,但不能为其他类型猜测它们。

def extract[T: LineDecoder : ClassTag](): Array[T] = ...应该代替def extract[T: LineDecoder](): ArraySeq[T] = ....

于 2019-11-20T18:57:29.103 回答