Scala 使用Shapeless将列表[字符串]转换为案例类

Scala 使用Shapeless将列表[字符串]转换为案例类,scala,scalaz,shapeless,Scala,Scalaz,Shapeless,我想知道是否有人能就我遇到的问题提供一些见解。我已经用一些代码和对我的问题的解释做了一个要点: 基本上,我正在尝试制作一些东西,允许我将List[String]转换为case类。我制作了一个允许我这样做的读取器,但我遇到了这样一个问题:为case类定义的读取器不能包含单独case类的读取器 看看下面的“非工作示例”-我遇到了一个问题,在阅读时,我不知道要从列表中拉出多少项。对于包含测试的Bar,我需要拉出2个元素(因为测试有两个参数)。有没有一种方法可以让我从case类的类型中知道它的字段数量?

我想知道是否有人能就我遇到的问题提供一些见解。我已经用一些代码和对我的问题的解释做了一个要点:

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

看看下面的“非工作示例”-我遇到了一个问题,在阅读时,我不知道要从列表中拉出多少项。对于包含测试的Bar,我需要拉出2个元素(因为测试有两个参数)。有没有一种方法可以让我从case类的类型中知道它的字段数量?有更好的方法吗

下面是一个如何使用阅读器的示例。我还包括了一个不起作用的例子

  ////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"))
  //////////////////////////

像这样的东西对我很有用(修改)

对象无形状StringToTypeConverters{
导入cats.\u,隐式.\u,data.ValidatedNel
导入鼠标。\u,字符串。\u,选项_
导入无形状。uu,带标签_
私有类型结果[A]=ValidatedNel[ParseFailure,A]
案例类解析失败(错误:字符串)
特征转换[V]{
def解析(输入:字符串):结果[V]
}
对象转换{
def to[V](输入:字符串)(隐式C:Convert[V]):结果[V]=
C.parse(输入)
def实例[V](正文:字符串=>结果[V]):转换[V]=新转换[V]{
def解析(输入:字符串):结果[V]=正文(输入)
}
隐式def booleans:Convert[Boolean]=
Convert.instance(
s=>
s、 解析布尔验证
.leftMap(e=>ParseFailure(s“不是布尔值${e.getMessage}”))
.toValidatedNel)
隐式定义整数:转换[Int]=
Convert.instance(
s=>
s、 parseIntValidated
.leftMap(e=>ParseFailure(s“不是Int${e.getMessage}”))
.toValidatedNel)
隐式定义长:转换[长]=
Convert.instance(
s=>
s、 parseLongValidated
.leftMap(e=>ParseFailure(s“不是长的${e.getMessage}”))
.toValidatedNel)
隐式def Double:Convert[Double]=
Convert.instance(
s=>
s、 解析双重验证
.leftMap(e=>ParseFailure(s“不是双精度${e.getMessage}”))
.toValidatedNel)
隐式定义字符串:Convert[String]=Convert.instance(s=>s.validNel)
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
密封特征模式映射[A]{
def readFrom(输入:Map[String,String]):ValidatedNel[ParseFailure,A]
}
对象模式映射{
[A]的定义(隐式s:SchemaMap[A]):SchemaMap[A]=s
私有def实例[A](body:Map[String,String]=>Result[A]):SchemaMap[A]=newschemamap[A]{
def readFrom(输入:映射[String,String]):结果[A]=
正文(输入)
}
隐式valnoop:SchemaMap[HNil]=
SchemaMap.instance(=>HNil.validNel)
隐式def解析[K转换为[V](条目),解析失败(s“$fieldName丢失”).invalidNel)
.map(f=>字段[K](f))
(parsedField,next.readFrom(input)).mapN(::u41;
}
隐式def类[A,R]
schema.readFrom(input.map)(x=>repr.from(x))
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
图式主义者[A]{
def readFrom(输入:List[String]):ValidatedNel[ParseFailure,A]
}
对象图式主义者{
[A]的定义(隐式s:SchemaList[A]):SchemaList[A]=s
私有def实例[A](body:List[String]=>Result[A]):模式主义者[A]=新模式主义者[A]{
def readFrom(输入:列表[字符串]):结果[A]=正文(输入)
}
隐式val noOp:图式主义者[HNil]=
SchemaList.instance(=>HNil.validNel)
隐式def解析[K转换为[V](条目),解析失败(s“$fieldName丢失”).invalidNel)
.map(f=>字段[K](f))
(parsedField,next.readFrom(input.tail)).mapN(::u41;
}
隐式def类[A,R]
schema.readFrom(input.map)(x=>repr.from(x))
}
}
}
/*
case类Foo(a:String,b:Int,c:Boolean)
defm: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=列表(“145164983”、“0.01862523”、“16.11681596”、“21:38:57”、“投标”)
案例类Trade0(tid:Long,价格:Double,金额:Double,时间:String,tpe:String)
val result2=SchemaList.of[Trade0].readFrom(lst)
*/
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)
*/