以类型安全的方式将Seq [String]转换为case类

pom*_*tee 6 scala scalaz shapeless

我编写了一个解析器,它根据一些规则将String转换为Seq [String].这将在库中使用.

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

我曾经想过无形的库,因为它似乎实现了很好的功能,看起来很成熟,但我不知道如何继续.

我发现这个问题有一个有趣的答案,但我找不到如何根据我的需要改造它.实际上,在答案中只有一种类型要解析(String),并且库在String本身内部迭代.它可能需要对事情的完成方式进行深刻的改变,我不知道如何做.

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

我对类型系统和所有这些美好的东西有点新,如果有人能给我一个如何做的建议,我会很开心!

亲切的问候

---编辑---

正如ziggystar所要求的,这里有一些可能需要的签名:

//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]       
 }
}    
Run Code Online (Sandbox Code Playgroud)

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

可能还有其他方式来设计它.这是我玩Shapeless几个小时后的想法.

DCK*_*ing 0

这个答案不会告诉你如何准确地做你想做的事,但它会解决你的问题。我认为你把事情过于复杂化了。

你想做什么?在我看来,您只是在寻找一种序列化反序列化案例类的方法 - 即,将 Scala 对象转换为通用字符串格式,然后将通用字符串格式转换回 Scala 对象。您目前的序列化步骤似乎已经定义了,并且您正在询问如何进行反序列化。

Scala 有一些可用的序列化/反序列化选项。您不必使用 Shapeless 或 Scalaz 自行完成。尝试看看这些解决方案:

  1. Java序列化/反序列化。Java 环境提供的常规序列化/反序列化工具。需要显式转换并且无法控制序列化格式,但它是内置的并且不需要太多工作来实现。
  2. JSON序列化:有很多库为Java提供JSON生成和解析。例如play-json,看看spray-jsonArgonaut 。
  3. Scala Pickling库是一个更通用的序列化/反序列化库。它开箱即用,带有一些二进制和一些 JSON 格式,但您可以创建自己的格式。

在这些解决方案中,至少play-jsonScala Pickling 使用宏 在编译时为您生成序列化器和反序列化器。这意味着它们应该既是类型安全的又是高性能的。