我编写了一个解析器,它按照一些规则将String转换为Seq [String]。这将在库中使用。
我正在尝试将此Seq [String]转换为case类。案例类将由用户提供(因此无法猜测它将是什么)。
我曾想过无形的库,因为它似乎实现了很好的功能,看起来很成熟,但我不知道如何继续。
我发现了这个问题with an interesting answer,但我找不到如何根据我的需要改造它。实际上,在答案中只有一种类型要解析(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]
}
}
在库内部有一些隐式的可用于将String转换为正确的类型,因为它们是由Shapeless猜测的(类似于上面链接中提出的答案)。像string.toInt,string.ToDouble等......
可能有其他方式来设计它。这是我在玩Shapeless几个小时后的想法。
答案 0 :(得分:1)
这使用了一个名为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))
并以另一种方式序列化:
scala> res28.csvIterator.toList
res30: List[String] = List(1,2,"toto", 3,4,"titi")
product-collections面向csv和java.io.Reader,因此是上面的垫片。
答案 1 :(得分:0)
这个答案不会告诉你如何做你想要的,但它会解决你的问题。我认为你过度复杂了。
你想做什么?在我看来,您只是在寻找 serialize 和反序列化案例类的方法 - 即将您的Scala对象转换为通用字符串格式和返回Scala对象的通用字符串格式。您的序列化步骤目前是您已经定义的,并且您正在询问如何进行反序列化。
Scala有一些序列化/反序列化选项。你不必用Shapeless或Scalaz来自己做。试着看看这些解决方案:
play-json
,spray-json
和Argonaut。在这些解决方案中,至少play-json
和Scala Pickling在编译时使用宏来生成序列化器和反序列化器。这意味着它们应该是类型安全和高效的。