鉴于此案例类run_pending()
以及字符串列表case class Location(id: BigInt, lat: Double, lng: Double)
我希望以List("87222", "42.9912987", "-93.9557953")
的方式执行类似Location.fromString(listOfString)
实例的创建,并将字符串类型转换为适当的类型。
我能想到的唯一方法是在每个案例类中定义Location
方法,但我正在寻找每个类可以继承的更通用的解决方案。例如,我会fromString
,其中case class Location(...) extends Record
实现Record
,它根据fromString
类中定义的参数类型进行转换。
答案 0 :(得分:2)
通常为了获得最佳性能,您需要创建一些宏。
幸运的是,有一个漂亮的shapeless library,您可以使用it's generic case class representation
立即创建具有近乎宏观性能的通用阅读器首先定义类型类和一些用于读取字段的实例:
trait Read[T] {
def fromString(s: String): T
}
implicit object readBigInt extends Read[BigInt] {
def fromString(s: String): BigInt = BigInt(s)
}
implicit object readDouble extends Read[Double] {
def fromString(s: String): Double = s.toDouble
}
接下来定义主类型类:
trait ReadSeq[T] {
def fromStrings(ss: Seq[String]): T
}
现在它是没有形状的时间(想想达利?)。我们为强大的Heterogenous List创建了阅读器,它几乎就像List
但具有静态已知的长度和元素类型。
与简单的List
匹配并不困难。只需为空列表和缺点定义案例:
import shapeless._
implicit object readHNil extends ReadSeq[HNil] {
def fromStrings(ss: Seq[String]) = HNil
}
implicit def readHList[X, XS <: HList](implicit head: Read[X], tail: ReadSeq[XS]) =
new ReadSeq[X :: XS] {
def fromStrings(ss: Seq[String]) = ss match {
case s +: rest => (head fromString s) :: (tail fromStrings rest)
}
}
现在我们可以通过HList
使用Generic
和案例类的开箱即用宏映射:
implicit def readCase[C, L <: HList](implicit gen: Generic.Aux[C, L], read: ReadSeq[L]) =
new ReadSeq[C] {
def fromStrings(ss: Seq[String]) = gen.from(read.fromStrings(ss))
}
最后,我们可以构建我们的类型类用户:
def fromStringSeq[T](ss: Seq[String])(implicit read: ReadSeq[T]) = read.fromStrings(ss)
从这一点开始
case class Location(id: BigInt, lat: Double, lng: Double)
val repr = List("87222", "42.9912987", "-93.9557953")
你可以确保
fromStringSeq[Location](repr) == Location(BigInt("87222"), 42.9912987, 93.9557953)