k47.cz  — každý den dokud se vám to nezačne líbit
výběr foto Praha povídky kultura
TECH ▞▞ kolo | twitter RSS

Scala - konverze TupleN na case class

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

V pro­jektu cha­n­mi­ner po­u­ží­vám pro do­ta­zo­vání re­lační da­ta­báze Sca­la­Query, která vrací in­stance TupleN neboli uspo­řá­dané n-tice (a tak je to správně). Někdy je po­třeba pře­vést tuto n-tici na objekt určité třídy, která má všechny po­třebné metody a „po­pisná jména člen­ských pro­měn­ných .(místo nic­ne­ří­ka­jí­cích _1, _2 atd.)“.

Před­stavte si, že mám třídu Post:

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

Da­ta­bá­zový dotaz mi vrátí Tuple7[Int, String, Int, Int, String, String, String] jako na­pří­klad:

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

Pře­ve­dení n-tice na in­stanci třídy není nijak zvlášť za­peklité:

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ů pat­tern 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í fun­guje, ale je zdlou­havé a s každým dalším prvkem v n-tici/třídě při­bude dal­ších pár znaků.

Na­štěstí máme při ruce zázrak kon­verze metody na funkční objekt a jeho metodu tupled + fakt, že každá case class má svůj com­pa­nion objekt s me­to­dou apply, která slouží jako zkrá­cený kon­t­ruk­tor (však víte: Post(...) se ex­pan­duje na Post.apply(...) a apply volá new Post(...)).

Takže když tohle všechno víme, můžeme kon­verzi pro­vé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ě­ko­lik pod­tr­ží­tek více:

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

Pří­padně si tuto metodu de­fi­no­vat přímo na com­pa­nion ob­jektu:

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