从字符串类型参数列表中创建对象实例

时间:2015-11-09 17:15:17

标签: scala

鉴于此案例类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类中定义的参数类型进行转换。

1 个答案:

答案 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)