以类型安全的方式将 Seq[String] 转换为 case 类 [英] Convert a Seq[String] to a case class in a typesafe way

查看:27
本文介绍了以类型安全的方式将 Seq[String] 转换为 case 类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个解析器,它按照一些规则将字符串转换为 Seq[String].这将用于图书馆.

I have written a parser which transforms a String to a Seq[String] following some rules. This will be used in a library.

我正在尝试将此 Seq[String] 转换为案例类.案例类将由用户提供(因此无法猜测它将是什么).

I am trying to transform this Seq[String] to a case class. The case class would be provided by the user (so there is no way to guess what it will be).

我想到了 shapeless 库,因为它似乎实现了很好的功能并且看起来很成熟,但我不知道如何进行.

I have thought to shapeless library because it seems to implement the good features and it seems mature, but I have no idea to how to proceed.

我发现这个问题有一个有趣的答案,但我没有找到如何根据我的需要对其进行转换.实际上,在答案中只有一种类型要解析(字符串),并且库在字符串本身内部进行迭代.这可能需要彻底改变做事的方式,而我不知道如何做.

I have found this question with an interesting answer but I don't find how to transform it for my needs. Indeed, in the answer there is only one type to parse (String), and the library iterates inside the String itself. It probably requires a deep change in the way things are done, and I have no clue how.

此外,如果可能的话,我想让我图书馆的用户尽可能轻松地完成这个过程.因此,如果可能的话,与上面链接中的答案不同,HList 类型将从 case 类本身猜测(但是根据我的搜索,编译器似乎需要此信息).

Moreover, if possible, I want to make this process as easy as possible for the user of my library. So, if possible, unlike the answer in link above, the HList type would be guess from the case class itself (however according to my search, it seems the compiler needs this information).

我对类型系统和所有这些美丽的东西有点陌生,如果有人能够就如何做给我建议,我会很高兴!

I am a bit new to the type system and all these beautiful things, if anyone is able to give me an advice on how to do, I would be very happy!

亲切的问候

--- 编辑---

根据 ziggystar 的要求,这里有一些可能需要的签名:

As ziggystar requested, here is some possible of the needed signature:

//Let's say we are just parsing a CSV.

@onUserSide
case class UserClass(i:Int, j:Int, s:String)
val list = Seq("1,2,toto", "3,4,titi")

// User transforms his case class to a function with something like:
val f = UserClass.curried

// The function created in 1/ is injected in the parser
val parser = new Parser(f)

// The Strings to convert to case classes are provided as an argument to the parse() method.
val finalResult:Seq[UserClass] = parser.parse(list) 
// The transfomation is done in two steps inside the parse() method:
// 1/ first we have: val list = Seq("1,2,toto", "3,4,titi")
// 2/ then we have a call to internalParserImplementedSomewhereElse(list)
//    val parseResult is now equal to Seq(Seq("1", "2", "toto"), Seq("3","4", "titi"))
// 3/ finally Shapeless do its magick trick and we have Seq(UserClass(1,2,"toto"), UserClass(3,4,"titi))



@insideTheLibrary
class Parser[A](function:A) {

 //The internal parser takes each String provided through argument of the method and transforms each String to a Seq[String]. So the Seq[String] provided is changed to Seq[Seq[String]]. 
 private def internalParserImplementedSomewhereElse(l:Seq[String]): Seq[Seq[String]] = {
  ...
 }

 /*
 * Class A and B are both related to the case class provided by the user: 
 * - A is the type of the case class as a function, 
 * - B is the type of the original case class (can be guessed from type A).
 */
 private def convert2CaseClass[B](list:Seq[String]): B {
    //do  something with Shapeless
    //I don't know what to put inside ???
 }

 def parse(l:Seq[String]){
   val parseResult:Seq[Seq[String]] = internalParserImplementedSomewhereElse(l:Seq[String])
   val finalResult = result.map(convert2CaseClass)
   finalResult // it is a Seq[CaseClassProvidedByUser]       
 }
}    

在库内部,一些隐式可用于将 String 转换为正确的类型,因为它们被 Shapeless 猜到了(类似于上面链接中提出的答案).像string.toInt、string.ToDouble等等...

Inside the library some implicit would be available to convert the String to the correct type as they are guessed by Shapeless (similar to the answered proposed in the link above). Like string.toInt, string.ToDouble, and so on...

可能还有其他设计方式.这正是我玩了 Shapeless 几个小时后想到的.

May be there are other way to design it. It's just what I have in mind after playing with Shapeless few hours.

推荐答案

这使用了一个非常简单的库,名为 product-集合

This uses a very simple library called product-collecions

import com.github.marklister.collections.io._
case class UserClass(i:Int, j:Int, s:String)

val csv = Seq("1,2,toto", "3,4,titi").mkString("\n")
csv: String =
1,2,toto
3,4,titi

CsvParser(UserClass).parse(new java.io.StringReader(csv))
res28: Seq[UserClass] = List(UserClass(1,2,toto), UserClass(3,4,titi))

并以另一种方式序列化:

And to serialize the other way:

scala> res28.csvIterator.toList
res30: List[String] = List(1,2,"toto", 3,4,"titi")

product-collections 面向 csv 和 java.io.Reader,因此是上面的垫片.

product-collections is orientated towards csv and a java.io.Reader, hence the shims above.

这篇关于以类型安全的方式将 Seq[String] 转换为 case 类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆