scala case class 這時候該怎麼用?
case class data(a: Int, b: String, c: String, d: Int, e: Int)
val arr =line.split(" ")
data(arr(0), arr(1), arr(2), arr(3), arr(4))
// 目前項目中的表非常大,如果array裡面有幾十個那該怎麼寫,請問大神們有沒有更好的辦法啊?
為了回答樓主的新問題,我特意給 shapeless 發了個 Pull Request #598,現在已經合併到 shapeless 2.3.2中。
用我這個Pull Request的話,大概可以這樣寫:
case class data(a: Int, b: String, c: String, d: Int, e: Int)
val arr = line.split(" ")
val i = arr.iterator
import shapeless._
object readField extends shapeless.Poly0 {
implicit def readInt = at[Int](i.next.toInt)
implicit def readString = at[String](i.next)
}
Generic[data].from(HList.fillWith[the.`Generic[data]`.Repr](readField))
----------------------------------------
原問題:
case class data(a: Int, b: Int, c: Int, d: Int, e: Int)
val arr = line.split(" ")
data(arr(0), arr(1), arr(2), arr(3), arr(4))
// 目前項目中的表非常大,如果array裡面有幾十個那該怎麼寫,請問大神們有沒有更好的辦法啊?
原答案:
黑科技來了:
case class data(a: Int, b: Int, c: Int, d: Int, e: Int)
val arr = "1 2 3 4 5".split(" ")
val myData = arr.foldLeft[Any](data.curried) { (f, s) =&>
f.asInstanceOf[Int =&> Any](s.toInt)
}.asInstanceOf[data]
注意,本代碼純屬娛樂,寫得很污,請勿模仿!
OK,讓我們一勞永逸的解決這個問題吧,讓大家見識一下Scala的強大:
給定一個字元串,自動轉換為需要的case class比如:- 給定字元串"zhangsan,100,34",定義了case class Person(name: String, id: Int, age: Int),就能自動由字元串得到Person(zhangsan, 100, 34)
- 給定字元串"100,300,400",定義了case class Vec(x: Int, y: Int, z: Int),就能自動由字元串得到Vec(100, 300, 400)
首先給出最終的實現效果:
@ case class Person(name: String, id: Int, age: Int)
defined class Person
@ Str2Class[Person]("ZhangSan,888,33").get
res3: Person = Person("ZhangSan", 888, 33)
@ case class Vec(x: Int, y: Int, z: Int)
defined class Vec
@ Str2Class[Vec]("100,200,300").get
res5: Vec = Vec(100, 200, 300)
object Str2Class {
import util.{ Failure, Success, Try }
trait Conveter[A] { def convert(text: String): Try[A] }
object Conveter {
def apply[A](implicit c: Conveter[A]): Conveter[A] = c
implicit object s2s extends Conveter[String] {
def convert(text: String) = Try(text)
}
implicit object s2i extends Conveter[Int] {
def convert(text: String) = Try(text.toInt)
}
}
import shapeless._
trait Parser[R &<: HList] { def parse(xs: Seq[String]): Try[R] }
object Parser {
def apply[R &<: HList](implicit p: Parser[R]) = p
def fromFun[R &<: HList](f: Seq[String] =&> Try[R]): Parser[R] = new Parser[R] {
def parse(xs: Seq[String]) = f(xs)
}
implicit object HNilParser extends Parser[HNil] {
def parse(xs: Seq[String]): Try[HNil] = xs match {
case Seq() =&> Success(HNil)
case _ =&> Failure(new RuntimeException("More items than expected."))
}
}
implicit def hListParser[A: Conveter, R &<: HList : Parser]: Parser[A :: R] = fromFun {
case x +: rs =&> for(xv &<- Conveter[A].convert(x);rv &<- Parser[R].parse(rs)) yield xv::rv
case Seq() =&> Failure(new RuntimeException("Less items than expected."))
}
}
trait LineParser[A] {
def apply[R &<: HList](text: String)
(implicit gen: Generic.Aux[A, R], p: Parser[R]): Try[A] =
p.parse(text.split(",")) map (gen.from)
}
def apply[A] = new LineParser[A]{}
}
==================原回答===================
Here we go:
@ import shapeless._
@ import syntax.std.traversable._
@ import syntax.std.tuple._
@ case class data(a: Int, b: Int, c: Int, d: Int, e: Int)
defined class data
@ type DATA = Int :: Int :: Int :: Int :: Int :: HNil
defined type DATA
@ val arr = "1 2 3 4 5".split(" ").map(_.toInt)
arr: Array[Int] = Array(1, 2, 3, 4, 5)
@ val myData = data.tupled(arr.toHList[DATA].get.tupled)
myData: data = data(1, 2, 3, 4, 5)
https://issues.scala-lang.org/browse/SI-7296
limit of 22 是因為apply和unapply的參數個數限制(FunctionN),不知道你怎麼使用case class,不需要pattern matching的話,直接用constructor,不要用case class了;否則的話按照 @neo lin的做法(嵌套)去restructure,或換版本。[雖然用implicit arguments 可以減少fields,但是這是坑不要踩]------------------------------------------一般的ORM框架對injection data的做法就是用反射了 case class data(a: Int, b: Int, c: Int, d: Int, e: Int)
val arr = "1 2 3 4 5".split(" ").map(_.toInt)
//調用constructor
val ru = scala.reflect.runtime.universe
val dataConstr = ru.runtimeMirror(
getClass.getClassLoader
).reflectClass(
ru.typeOf[data].typeSymbol.asClass
).reflectConstructor(
ru.typeOf[data].declaration(ru.nme.CONSTRUCTOR).asMethod
)
println(dataConstr(arr: _*))
//or 調用apply方法
val m = ru.runtimeMirror(getClass.getClassLoader)
val methodApply = m.reflect(
m.reflectModule(ru.typeOf[data.type].termSymbol.asModule).instance
).reflectMethod(
ru.typeOf[data.type].declaration(ru.newTermName("apply")).asMethod
)
println(methodApply(arr: _*))
忘了現在最新版有沒有22個值的上限。
用嵌套,或者合理劃分你的類型。題主改問題了,請參考HList的那套答案。瀉藥了。推薦閱讀:
※代數數據類型是什麼?
※kotlin和scala兩種語言的對比?
※如何看待TIOBE2016年預測scala將停留在前20內?
※模式匹配是語法糖嗎?
※如何評價scalaz這個庫?