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

标签 scala scalaz shapeless

我编写了一个解析器,它按照一些规则将 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/

相关文章:

Scala - Flatmap 一系列选项和可遍历

scala - 如何在 Spark SCALA 中重命名 AWS 中的 Spark 数据帧输出文件

Scalaz - 无法取消应用类型 StateT[Future, Foo, Bar]

scala - 作家单子(monad)实际上与状态单子(monad)相同吗?

scala - 通用实体记录 scala - 引入无形状的 id 字段

scala - 将多个 WS 调用合并为一个结果时处理错误

scala - 有没有像 Scala 内置的 Haskell 的 'maybe' 函数?

scala - 需要什么方法来创建自定义 Applicative Functor 以与 scalaz 一起使用 |@|

scala - 子集和无形可扩展记录

scala - Scala 中类型不相等的证据