【问题标题】:Convert a List[String] to a case class using Shapeless使用 Shapeless 将 List[String] 转换为案例类
【发布时间】:2018-02-10 23:32:13
【问题描述】:

我想知道是否有人可以就我遇到的问题提供一些见解。我用一些代码和对我的问题的解释做了一个要点:https://gist.github.com/tbrown1979/9993f07c8f4fa2786c83

基本上,我正在尝试制作一些允许我将 List[String] 转换为案例类的东西。我已经制作了一个允许我这样做的阅读器,但我遇到了为案例类定义的阅读器不能包含单独案例类的阅读器的问题。

查看下面的“无效示例” - 我遇到一个问题,在阅读时,我不知道要从列表中拉出多少项目。使用包含测试的 Bar,我需要拉出 2 个元素(因为测试有两个参数)。有没有办法让我知道案例类仅从其类型中具有的字段数量?有一个更好的方法吗?

以下是如何使用阅读器的示例。我也包含了一个无效的示例。

  ////Working Example////
  case class Foo(a: Int, s: String)
  object Foo {
    implicit val FooReader : Reader[Foo] =
      Reader[Int :: String :: HNil].map(Generic[Foo].from _)
  }

  val read: ValidationNel[String, Foo] = Reader.read[Foo](List("12","text"))
  println(read)//Success(Foo(12, "text"))
  ///////////////////////////

  ////Non-working Example////
  case class Test(a: Int, b: String)
  object Test {
    implicit val TestReader: Reader[Test] =
      Reader[Int :: String :: HNil].map(Generic[Test].from _)
  }

  case class Bar(c: Test)
  object Bar {
    implicit val BarReader: Reader[Bar] =
      Reader[Test :: HNil].map(Generic[Bar].from _)
  }

  val barRead = Reader.read[Bar](List("21", "someString"))
  println(barRead) //Failure(NonEmptyList("Invalid String: List()", "Exepected empty, but contained value"))
  //////////////////////////

【问题讨论】:

    标签: scala scalaz shapeless


    【解决方案1】:

    这样的东西对我有用(修改this

    object ShapelessStringToTypeConverters {
    
      import cats._, implicits._, data.ValidatedNel
      import mouse._, string._, option._
      import shapeless._, labelled._
    
      private type Result[A] = ValidatedNel[ParseFailure, A]
    
      case class ParseFailure(error: String)
    
      trait Convert[V] {
        def parse(input: String): Result[V]
      }
    
      object Convert {
        def to[V](input: String)(implicit C: Convert[V]): Result[V] =
          C.parse(input)
    
        def instance[V](body: String => Result[V]): Convert[V] = new Convert[V] {
          def parse(input: String): Result[V] = body(input)
        }
    
        implicit def booleans: Convert[Boolean] =
          Convert.instance(
            s =>
              s.parseBooleanValidated
                .leftMap(e => ParseFailure(s"Not a Boolean ${e.getMessage}"))
                .toValidatedNel)
    
        implicit def ints: Convert[Int] =
          Convert.instance(
            s =>
              s.parseIntValidated
                .leftMap(e => ParseFailure(s"Not an Int ${e.getMessage}"))
                .toValidatedNel)
    
        implicit def longs: Convert[Long] =
          Convert.instance(
            s =>
              s.parseLongValidated
                .leftMap(e => ParseFailure(s"Not an Long ${e.getMessage}"))
                .toValidatedNel)
    
        implicit def doubles: Convert[Double] =
          Convert.instance(
            s =>
              s.parseDoubleValidated
                .leftMap(e => ParseFailure(s"Not an Double ${e.getMessage}"))
                .toValidatedNel)
    
        implicit def strings: Convert[String] = Convert.instance(s => s.validNel)
      }
    
      //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      sealed trait SchemaMap[A] {
        def readFrom(input: Map[String, String]): ValidatedNel[ParseFailure, A]
      }
    
      object SchemaMap {
        def of[A](implicit s: SchemaMap[A]): SchemaMap[A] = s
    
        private def instance[A](body: Map[String, String] => Result[A]): SchemaMap[A] = new SchemaMap[A] {
          def readFrom(input: Map[String, String]): Result[A] =
            body(input)
        }
    
        implicit val noOp: SchemaMap[HNil] =
          SchemaMap.instance(_ => HNil.validNel)
    
        implicit def parsing[K <: Symbol, V: Convert, T <: HList](implicit key: Witness.Aux[K], next: SchemaMap[T]): SchemaMap[FieldType[K, V] :: T] =
          SchemaMap.instance { input =>
            val fieldName = key.value.name
            val parsedField = input
              .get(fieldName)
              .cata(entry => Convert.to[V](entry), ParseFailure(s"$fieldName is missing").invalidNel)
              .map(f => field[K](f))
    
            (parsedField, next.readFrom(input)).mapN(_ :: _)
          }
    
        implicit def classes[A, R <: HList](implicit repr: LabelledGeneric.Aux[A, R], schema: SchemaMap[R]): SchemaMap[A] =
          SchemaMap.instance { input =>
            schema.readFrom(input).map(x => repr.from(x))
          }
      }
    
      //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      sealed trait SchemaList[A] {
        def readFrom(input: List[String]): ValidatedNel[ParseFailure, A]
      }
    
      object SchemaList {
        def of[A](implicit s: SchemaList[A]): SchemaList[A] = s
    
        private def instance[A](body: List[String] => Result[A]): SchemaList[A] = new SchemaList[A] {
          def readFrom(input: List[String]): Result[A] = body(input)
        }
    
        implicit val noOp: SchemaList[HNil] =
          SchemaList.instance(_ => HNil.validNel)
    
        implicit def parsing[K <: Symbol, V: Convert, T <: HList](implicit key: Witness.Aux[K], next: SchemaList[T]): SchemaList[FieldType[K, V] :: T] =
          SchemaList.instance { input =>
            val fieldName = key.value.name
            val parsedField = input
              .headOption
              .cata(entry => Convert.to[V](entry), ParseFailure(s"$fieldName is missing").invalidNel)
              .map(f => field[K](f))
    
            (parsedField, next.readFrom(input.tail)).mapN(_ :: _)
          }
    
        implicit def classes[A, R <: HList](implicit repr: LabelledGeneric.Aux[A, R], schema: SchemaList[R]): SchemaList[A] =
          SchemaList.instance { input =>
            schema.readFrom(input).map(x => repr.from(x))
          }
      }
    }
    
    /*
        case class Foo(a: String, b: Int, c: Boolean)
        def m: Map[String, String] = Map("a" -> "hello", "c" -> "true", "b" -> "100")
        def e: Map[String, String] = Map("c" -> "true", "b" -> "a100")
        val result = SchemaMap.of[Foo].readFrom(m)
    
        val lst = List("145164983", "0.01862523", "16.11681596", "21:38:57", "bid")
        case class Trade0(tid: Long, price: Double, amount: Double, time: String, tpe: String)
        val result2 = SchemaList.of[Trade0].readFrom(lst)
    */
    

    【讨论】:

      猜你喜欢
      • 2015-10-16
      • 2015-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-11
      • 2021-09-17
      • 1970-01-01
      相关资源
      最近更新 更多