03 - "Hello " + "Scala"

Típusos értékek

Láttuk, hogy értékeket tudunk deklarálni a val kulcsszóval. Ha pl. a Hello Scala kiíró kódunkban a kiírandó stringet egy értékbe elrakjuk, az így fest:

1
2
3
4
object Hello extends App {
  val hello: String = "Hello Scala"
  println( hello )
}

Persze mindez a Hello objektum törzsében.

Amit érdemes észrevenni:

  • Még mindig nincs pontosvessző, arra nagyon ritkán lesz szükségünk.
  • Van Scalában olyan típus, aminek a neve String és szöveget tud tárolni. (ez a típus egyébként teljesen ugyanaz, mint a Java-féle java.lang.String)

A Scala típuskövetkeztetője (és az az alapján hibaüzik generálása) látni fogjuk, hogy elég erős, és sokféle módon lehet újabb és újabb típusokat gyártani.

Például, ha egy érték deklarálásnál ki tudja következtetni a fordító a jobb oldalból annak a típusát, és az nekünk meg is felel, amit kikövetkeztet, akkor nem vagyunk kötelesek megadni az érték típusát explciten. Mivel pedig a "Hello Scala" az egyenlőség jobb oldalán egyértelműen egy String literál, ezért a jobb oldali kifejezés típusa String. Ha tehát nem írjuk ki az érték deklarálásnál a típust, akkor a fordító úgy veszi, hogy az ott egy String:

1
2
3
4
object Hello extends App {
  val hello = "Hello Scala"
  println( hello )
}

Így is lefordul, és teljesen ugyanaz, mint az előző: a hello érték típusa így is String lesz. Az ilyet úgy hívják, hogy ennek a hello értéknek a String az inferred type-ja.

Típusok Scalában

Néhány fontosabb, gyakran használt típus Scalában, később még lesz róluk szó, amit tudunk hova kötni korábbi tanulmányaink alapján:

  • String - ugyanaz, mint a java.lang.String, szöveges információt tárol, karakterláncot, C-ben egy char[] állhat hozzá legközelebb
  • Char - karakter, egy darab Unicode karakter tárolására alkalmas, a Stringek Char-okból állnak, megfelel a Java char elemi típusának
  • Boolean - logikai típus, két érték rendelkezik ezzel a típussal, a true és a false, megfelel a Java boolean elemi típusának
  • Byte - 8-bites előjel nélküli egész szám típus, 0-255 közti egész számok tárolására alkalmas
  • Short - 16-bites előjeles egész szám típus, megfelel a Java short elemi típusának
  • Int - 32-bites előjeles egész szám típus, megfelel a Java int elemi típusának
  • Long - 64-bites előjeles egész szám típus, megfelel a Java long elemi típusának
  • Float - lebegőpontos szám, megfelel a Java vagy a C float elemi típusának
  • Double - dupla pontosságú lebegőpontos szám, megfelel a Java vagy a C double elemi típusának

És néhány olyan, ami talán kevésbé tűnik megfoghatónak:

  • Unit - ennek egyetlen lehetséges értéke a (), olyasmi, mint C-ben a void, legalábbis abban az értelemben, hogy ha valami ilyen típusú, akkor - mivel ebbe a típusba csak egyféle érték tartozik - automatikusan tudjuk az értékét, így biztos, hogy ha van egyáltalán értelme kiértékelni egy Unit típusú kifejezést, akkor ott nem a visszatérési érték lesz a lényeg, hanem valamiféle ,,mellékhatás''. A println() függvény például Unit típusra értékelődik ki: nem ad vissza semmi ,,meaningful'' értéket, és egyfajta ,,mellékhatásként'' kiírja az argumentumát a konzolra.
  • Null - ennek egyetlen lehetséges értéke a null, a nullpointer. Erre a típusra azért van szükség, hogy a nullpointernek tudjunk adni olyan típust, amire rá tudjuk majd mondani (a típushierarchián keresztül, lásd később), hogy ezt felveheti értékként bármilyen ,,pointer'' típus (amit Javában és Scalában is inkább ,,referenciának'' hívunk).
  • Nothing - ennek a típusnak nincs lehetséges értéke. Egyáltalán. Ennek a típusnak a bevezetése szintén azért lesz jó, mert ezzel el tudjuk majd érni, hogy ha egy függvény minden lehetséges inputra (mondjuk) kivételt dob, akkor végül is mindegy, hogy mi lenne a visszatérési értéke, lehet akár Nothing is, a Nothing meg azért lesz jó, mert az minden típusnak a leszármazottja lesz, így bárhova be fogjuk tudni helyettesíteni. Stay tuned.

Kifejezések építése függvényekkel

Scalában függvényekkel készíthetünk értékekből újabb értékeket. Egyes függvények előre le vannak nekünk definiálva, legalábbis bizonyos típusokra:

  • ha leírunk egy ilyet, hogy 3 + 7, akkor ez a + függvényt hívja meg két Int paraméterre, mert a 3 is egy Int és a 7 is egy Int literál (ezt majd kicsit később pontosítjuk), ennek a + függvénynek a kimenetí típusa pedig szintén Int (két int összege egy int), ezért a fordító ki tudja következtetni, hogy a 3+7 érték típusa Int lesz
  • és ezért tudunk írni olyat is, hogy val tiz = 3 + 7, ekkor a tiz egy Int típusú érték lesz (mégpedig a 10 számot fogja tárolni, ha így deklaráljuk)
  • Intek közt egyébként még a * (szorzás), - (kivonás), / (egészosztás: pl. 5/2=2, továbbra is Int) műveletek is nyelvi szinten definiáltak, az unáris mínusz is ellentettet képez, a kimenet szintén Int
  • az fontos, hogy egy-egy függvény vagy operátor milyen típusú inputra van meghívva (ezt hívják polimorfizmusnak: más bemeneti típusokra is lehet definiálva a függvény, és ha más típusú argumentumokkal hívjuk, akkor másképp működhet), például két String között az + függvény egy harmadik Stringet készít, mégpedig a kettő input string ,,konkatenáltját'', egymás után írását.

Így pl. ez is ugyanúgy kiírja a Hello Scala stringet, mint az eddigiek:

1
2
3
4
object Hello extends App {
  val hello = "Hello " + "Scala"
  println( hello )               //prints Hello Scala
}

Figyeljünk oda a szóközre, nem teszi oda magától.

Itt is egyszerű a típuskövetkeztetés: a "Hello " egy String literál, a "Scala" szintén az, az összeadás művelet két Stringből egy harmadik Stringet épít, ezért a hello érték típusa is String lesz.

Kérdések, feladatok


Utolsó frissítés: 2020-12-22 21:04:26