11 - trait: az összeg¶
A tuple és a case class a szorzat típus névre is hallgatnak, mert segítségükkel fel tudunk építeni olyan típust, melynek a lehetséges értéktartománya az "altípusok" értéktartományának Descartes-szorzatai.
Sokszor van igény arra is, hogy unió típust hozzunk létre: azaz ha van egy T1
típusunk, aminek az értéktartománya D1
, meg egy T2
típusunk, aminek az értéktartománya
D2
, és szeretnénk készíteni egy olyan T
típust, melynek értéktartománya D1 ⊎ D2
,
a két értéktartomány diszjunkt uniója. Ez azt jelenti, hogy ha van is átfedés a két
halmaz közt, akkor is minden elem az ,,eredeti típus infóval'' kerüljön bele, pl.
ha az Int
és a Long
típusokból szeretnénk készíteni egy unió típust, akkor szerepeljen
ennek az új típusnak az értéktartományában az int 0 is és a long 0 is külön-külön.
Ha ezt le tudjuk kódolni egy programozási nyelvben, akkor azt mondjuk, hogy az új
T
típus a T1
és T2
típusok összege, jelben T=T1+T2
. (A case class pedig
a két vagy több mezőtípusának a szorzata volt, pl. a 2D Pont típusunkra írhatjuk akár
azt, hogy Pont = Int x Int
.)
Háromszögek és körök C-ben¶
Hogy kicsit megfoghatóbb legyen: mondjuk, hogy van egy geometriai formákkal dolgozó appunk. Van benne pont, háromszög (ami három pontból tevődik össze), kör (ami egy középpontból és egy sugárból), pl. így:
1 2 3 4 |
|
Shape = Kor + Haromszog
típust létrehozni.
Ennek C-ben egy implementációja pl. így nézhet ki:
1 2 3 4 5 6 7 8 9 10 11 |
|
type
mezője tárolja,
hogy most épp kör vagy háromszög amire tulajdonképp mutatunk,
és ennek függvényében van vagy egy Kor
, vagy egy Haromszog
adatmezőnk,
de mivel egyszerre csak az egyik lehet valid, ezért őket unionba tesszük. Egy példa használata ennek az új típusnak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
...és Scalában¶
Ha a case classok a saját osztályaink, és módosíthatjuk a fejlécüket, akkor a legegyszerűbb
módja összeg típus létrehozásának egy trait
létrehozása:
1 2 3 4 5 |
|
Shape
, létrehozhatunk a trait
kulcsszóval, a létrejött típus ezen a ponton ,,üres''
* ha egy case class fejlécének végére odaírjuk, hogy extends
és egy trait nevét, akkor onnantól kezdve a megadott
trait adattartományába ez a case class is beletartozik
* nem kell plusz mezőt létrehoznunk, ami valamilyen értelemben ,,figyel'' arra, hogy egy Shape
típusú értékben
lévő konkrét objektum éppen kör vagy háromszög, ez automatikusan fog történni.
A fenti osztályok használatára gyors példa:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Shape
típussal deklarált értékünk,
akkor hogyan lehet megtudni belőle, hogy éppen milyen érték is van benne. A shape
érték deklarálásakor azért van
kiírva a Shape
típus expliciten, mert különben - mivel a jobb oldalon szereplő h
az egy Haromszog
- a Scala
fordító Haromszog
-re inferné. A traitek szintén több mindenre lesznek jók ezen kívül: egyelőre csak az a lényeg,
hogy tudunk létrehozni a beépített típusokból case classokkal és traitekkel szorzat és összeg típusokat, amikkel
pedig elérkezünk az algebrai adattípus fogalmáig, ami a funkcionális nyelvek egyik legfontosabb adatszerkezet-osztálya.