我编写了一个解析器,它按照一些规则将 String 转换为 Seq[String]。这将在图书馆中使用。
我正在尝试将此 Seq[String] 转换为案例类。案例类将由用户提供(因此无法猜测它将是什么)。
我考虑过 shapeless 库,因为它似乎实现了良好的功能并且看起来很成熟,但我不知道如何进行。
我发现了这个问题 with an interesting answer但我没有找到如何根据我的需要改造它。实际上,在答案中只有一种类型要解析(字符串),并且库在字符串本身内部进行迭代。它可能需要彻底改变做事的方式,而我不知道如何改变。
此外,如果可能的话,我想让我的图书馆用户尽可能轻松地完成这个过程。因此,如果可能的话,与上面链接中的答案不同,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 几个小时后想到的。
最佳答案
这使用了一个名为 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,因此是上面的垫片。
关于scala - 以类型安全的方式将 Seq[String] 转换为 case 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23540531/