k47.cz
mastodon twitter RSS
bandcamp explorer

Scala - konverze TupleN na case class

23. 3. 2012 (před 11 lety) — k47 (CC by-nc-sa)

V projektu chanminer používám pro dotazování relační databáze ScalaQuery, která vrací instance TupleN neboli uspořádané n-tice (a tak je to správně). Někdy je potřeba převést tuto n-tici na objekt určité třídy, která má všechny potřebné metody a „popisná jména členských proměnných .(místo nicneříkajících _1, _2 atd.)“.

Představte si, že mám třídu Post:

case class Post(
  uid: Int, board: String, threadId: Int, id: Int,
  postername: String, tripcode: String, text: String)

Databázový dotaz mi vrátí Tuple7[Int, String, Int, Int, String, String, String] jako například:

val t = (9, "b", 323822047, 323856408, "Anonymous", "", "reported")

Převedení n-tice na instanci třídy není nijak zvlášť zapeklité:

def makePost(t: (Int, String, Int, Int, String, String, String)) =
  Post(t._1, t._2, t._3, t._4, t._5, t._6, t._7)

Nebo s pomocí zázraků pattern matchingu:

def makePost2(t: (Int, String, Int, Int, String, String, String)) = {
  val (uid, board, threadId, id, postername, tripcode, text) = t
  Post(uid, board, threadId, id, postername, tripcode, text)
}

Tohle řešení funguje, ale je zdlouhavé a s každým dalším prvkem v n-tici/třídě přibude dalších pár znaků.

Naštěstí máme při ruce zázrak konverze metody na funkční objekt a jeho metodu tupled + fakt, že každá case class má svůj companion objekt s metodou apply, která slouží jako zkrácený kontruktor (však víte: Post(...) se expanduje na Post.apply(...) a apply volá new Post(...)).

Takže když tohle všechno víme, můžeme konverzi provést mnohem stručněji:

val makePostApply = (Post.apply _).tupled
val post: Post = makePostApply(t)

Pro obyčejné třídy musíme napsat o několik podtržítek více:

val makePostNew = (new Post(_, _, _, _, _, _, _)).tupled
val post: Post = makePostNew(t)

Případně si tuto metodu definovat přímo na companion objektu:

object Post {
  val fromTuple = (Post.apply _).tupled
}
píše k47, ascii@k47.cz