Mintaillesztést az ún. case osztályok példányain végezhetünk. Ilymódon a funkcionális programozási paradigmából ismert algebrai adatstruktúrákat építhetünk és dolgozhatunk fel kevés kód írásával.
Egy egyszerű példa case osztályra:
Implicit kapunk hozzá egy konstruktort, ahol az összes adattag megadható paraméterként. Ilymódon egy kicsit kevésbé lesz zajos a kód ha le szeretnénk írni egy összetettebb struktúrát, hiszen a felesleges new kulcsszavak megspórolhatók:
A toString, hashCode és equals műveletek előre implementáltak, méghozzá úgy, hogy a case osztály egy példányának struktráját veszik figyelembe, nem pedig az objektum referenciákat. A toString ekkor hasonlóan viselkedik a Haskell show függvényéhez. Értelemszerűen a
A case osztály összes adattagjára automatikusan kapunk lekérdező metódusokat.
Mintaillesztést a match kifejezéssel tudunk használni, amelynek a szintaxisa nagyban hasonlít a C stílusú nyelvek switch-case utasítására. Valójában a match a switch-case utasításnak az osztályhierarchiákra vett általánosítása. Ebből is látszik, hogy a Scala hogyan képes utánozni az egyes funkcionális nyelvi elemeket objektum orientált eszközökkel.
Itt a Number(x)
és a Sum(l,r)
a minták, amiket az e szelektorértékre illesztünk. Number(x)
felveszi az összes Number objektum értékét és az x
mintaváltozónak értékül adja az adott Numberben tárolt n egész számot. Összességében a működése nagyon jól követi a Haskellben ill. bármely más funkcionális nyelvben használatos mintaillesztését, hiszen itt is fentről lefelé próbálja végig a mintákat egy adott értékre amíg nem talál illeszkedést. Ellenkező esetben dob egy MatchError
kivételt.
A következőkből lehet mintákat építeni:
true
, "abc"
, 1
Lambda kifejezésekben is használhatunk mintaillesztést, sőt egy match kifejezés önmagában is egy névtelen függvény:
Ez átírható ekképp:
A mintaillesztés első ránézésre olyan, mintha Java-ban switch/case szerkezetet használnánk. A switch/case azonban csak primitív típusokra működik. Gyakran felmerül azonban az igény, hogy például String típusra használjuk. A Scala-ba nem került bele a switch/case helyette azonban jelen van a sokkal erősebb mintaillesztés.
Tekintsük azokat a bináris fákat, amelyek levelei egész számokat tartalmaznak. Legyen egy osztályunk a fáknak, és egy-egy alosztályunk a leveleknek és a csomópontoknak:
A Tree osztálynak nincs extends klóza és törzse sem. Ez a következővel ekvivalens:
A Tree mindkét leszármazottjának van case módosítója. Ennek két hatása van. Egyrészt a new kulcsszó elhagyásával hozhatunk létre objektumokat:
Másrészt a konstruktorok mintaillesztésre használhatóak:
A sumLeaves metódus összeadja a levelekben szereplő számokat. A match metódus az Object osztályban van definiálva. Paraméterként egy választó kifejezést vár. A case ágakban a változókhoz hozzárendelés is történik. A minta változók mindig kis betűvel, a konstruktorok pedig nagy betűvel kell kezdődjenek.
A választó kifejezés hatása a következő. Az első olyan alternatíva, melynek mintája megfelel a kiválasztó értéknek, törzse lesz kiértékelve, a mintaváltozók rögzítésre kerülnek.