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

Scala - pattern matching

7. 6. 2011 — k47 (CC by) (♪)

Seznam všechn způ­sobů, jak lze pro­vá­dět pat­tern matching:

a match {
  case a =>              // shoda pro jakoukoli hodnotu
  case _ =>              // to samé, ale bez pojmenované proměnné
  case a: Something =>   // case a if a.isInstanceOf[Something] && a != null  // pro null nikdy nenastane shoda
  case Something =>      // case a if a == Something, toto pravidlo je použito v případě `case None' nebo `case Nil'
  case Something() =>    // case a: Something
  case A(b) =>
  case `variable` =>     // case v if v == variable
  case A(`b`) =>         // case A(x) if x == b
  case A(B) =>           // case A(b) if b == B  // pokud název proměnné začíná velkým písmenem nebo je v zpětných apostrofech, bere se jako konstanta
  case A("string literal") => // lze použít jakýkoli literál (Int, String, Boolean, Char, Symbol)
  case A(a, B(C(c), b)) => // vzory lze libovolně vnořovat
  case A(_, a) =>        // pojmenovat můžeme jenom některé proměnné
  case A() | B() =>      // odpovídá jednomu ze dvou vzorů
  case A(_) | B(_, _) => // není možné pojmenovat parametry
  case b @ B(x, y) =>    // objekt B je zachycen do proměnné `b' a zároveň jsou zachyceny jeho dílčí části v `x' a `y'
  case B(a @ A(_), _) => // @ konstrukci lze pochopitelně libovolně zanořovat
  case a: Array[Int] =>  // můžeme se dotazovat na typový parametr polí
  case a: List[_] =>     // ale ne na typ. param. ostatních generických typů (jinak nás uvítá unchecked warning)

  // sekvence
  case List(0, 1, 2) =>  // seznam, který má délku 3 a obsahuje položky: 1, 2, 3
  case List(1, _, _) =>  // seznam, který má délku 3 a začíná integerem 1
  case List(1, _*) =>    // seznam délky > 1, který začíná integerem 1

  case (a, b, c) =>      // case Tuple3(a, b, c)
  case 1 :: Nil =>       // infixový vzor, obdoba `case List(1)' nebo přesněji `case ::(1, Nil)'
  case 1 :: 2 :: _ =>    // obdoba `case ::(1, ::(2, _)' nebo `case List(1, 2, _*)'
}

A nej­lepší je, že sou­kolí pat­tern matchingu můžete po­u­ží­vat i v de­fi­nici pro­měn­ných. Téměř všechno, co může ná­sle­do­vat case, může másle­do­vat val.

val myTuple = (123, "xxx")
val (a, b) = myTuple
val List(1, _, 3) = myList

do­konce můžete použít i ta­ko­vé­hle zrůd­nosti:

val a @ Some(b) = Some(1) // a = Some(1); b = 1

Ma­lič­kým pro­blé­mem může být, že pokud ne­na­stane shoda, uvítá vás přá­tel­ská MatchError.

Ještě jedna drob­nost: pokud de­fi­nu­jete třídu s ně­ko­lika sku­pi­nami ar­gu­mentů, pat­tern matching lze pro­vá­dět jen na první z nich.

case class A(a: Int)(b: String)

A(1)("something") match {
  case A(_)(_) => // není možné
  case A(_) =>    // tohle je už lepší
}
píše k47 & hosté, ascii@k47.cz