Muutettu viimeksi 29.2.2016 / Sivu luotu 18.3.2010 / [oppikirjan esimerkit] / [Scala]
Sivun sisältöä:
Scalan numeeriset tyypit on Bytecode-tasolla toteutettu Javan alkeistyyppeinä, joten ohjelmien suoritustehokkuuden pitäisi säilyä Java-tasoisena.
Scalassa numeeristen tyyppien operaatiovalikoimaa on rikastettu, ks. alla.
String-literaalivakioihin on tehty kirjoitusvaivoja säästävä lisäys: kolmikertaisin lainausmerkein voi kirjoittaa "raakatekstiä":
println("""Näin voi kirjoittaa tekstiä, joka sisältää vaikkapa rivinvaihtoja, "- ja \-merkkejä sellaisinaan tyhjiä rivejä yms, yms. vain kolminkertaista lainausmerkkiä ei voi olla...""")Tulostus:
Näin voi kirjoittaa tekstiä, joka sisältää vaikkapa rivinvaihtoja, "- ja \-merkkejä sellaisinaan tyhjiä rivejä yms, yms. vain kolminkertaista lainausmerkkiä ei voi olla...On ehkä tylsää saada nuo rivin alkujen välilyöntijonot "raakoina" mukaan. Apu löytyy pystyviivasta ja stripMargin-metodista:
println("""|Näin voi kirjoittaa tekstiä, joka sisältää vaikkapa |rivinvaihtoja, "- ja \-merkkejä sellaisinaan | | tyhjiä rivejä yms, yms. |vain kolminkertaista lainausmerkkiä ei voi olla...""".stripMargin)Tulostus:
Näin voi kirjoittaa tekstiä, joka sisältää vaikkapa rivinvaihtoja, "- ja \-merkkejä sellaisinaan tyhjiä rivejä yms, yms. vain kolminkertaista lainausmerkkiä ei voi olla...Huom: Javasta poiketen String-olioiden sisältöjen yhtäsuuruutta voi verrata ==-operaatiolla!
Symbolit ovat, ..., hmm..., ..., no symbolit ovat symboleja:
def sanoJotain(kuka:Symbol) { if (kuka=='kissa) println("Miau") else if (kuka=='koira) println("Hauhau") else println("Ammuu") } sanoJotain('possu) // Ammuu sanoJotain('kissa) // Miau sanoJotain('koira) // HauhauJuuri mitään muuta kuin samuuden kyselyä symboleille ei voi tehdä. Mutta tämähän on oikeastaan aika näppärä tapa toteuttaa erilaisia "ohjauskoodeja". Ei ainakaan tavitse itse koodata asioiden nimiä kokonaisluvuiksi tms. Puhumattakaan että joutuisi jotain Javan kamalaa "enumerated"-tyyppiä käyttämään.
println(1+2) // 3 println((1).+(2)) // 3 // nyt myös: println(1.+(2)) // muutama versio sitten tulkittiin doubleksi println("kukkapenkki".indexOf('p')) // 5 println("kukkapenkki" indexOf 'p' ) // 5Esimerkiksi Int-luokka sisältää useita erilaisia kuormitettuja versioita +-metodista: Vaikkapa kutsu 1+2L eli (1).+(2L) käynnistää sellaisen Int-luokassa määritellyn +-metodin, jonka parametri on tyyppiä Long.
Nähdyt esimerkit olivat infix-operaatioita: "operandi-operaatio-operandi". Muitakin on:
// näin kaksiparametrinen metodikutsu "infixataan": println("kukkapenkki".indexOf('k', 4)) // 8 println("kukkapenkki" indexOf ('k', 4)) // 8Prefix ja postfix:
// prefix: println(-7) // -7 println(7.unary_-) // -7 //postfix: import scala.language.postfixOps // nyt tarvitaan tämä! println("HUUDETAAN".toLowerCase) // huudetaan println("HUUDETAAN" toLowerCase) // huudetaanHuom: Ainoastaan merkkejä +, - ja ~ voi käyttää unaarisina prefix-operaatioina! Ne ohjelmoidaan metodeina unary_+, unary_- unary_~.
Esimerkki:
class Kissa { def unary_+ = "Miau" def unary_- = "Hyrr" def unary_~ = "Shhhhs" } val a = new Kissa println(+a) // Miau println(-a) // Hyrr println(~a) // Shhhhs // myös toki tyyliin: println(a.unary_+) // Miau
Asiat ovat lopulta aika samoin Scalassa. Tosin kaikki arvot ovat olioita ja ==- ja !=-operaatiot testaavat equals-samuutta! Ne suorastaan itse asiassa kutsuvat equals-metodia. Siispä esimerkiksi seuraavat vertailut ovat true:
"he"+"llo" == "hello" List(1, 2, 3) == List(1, 2, 3) "kukamitaha" != 3.14 // jopa siis keskenään eri tyyppisiä voi // verrata dynaamisten kielten tapaanVertailun vasemman puoleinen vertailtava määrää, minkä luokan equals-metodia kutsutaan.
Omiin luokkiin ohjelmoidut equals-metodit käyttäytyvät samaan tapaan:
class Otus (val nimi: String, val pituus: Int) { // pitäisi määritellä myös override def hashCode! override def equals(that: Any) = that match { case that: Otus => this.nimi == that.nimi && this.pituus == that.pituus case _ => false } } val a = new Otus("Aapeli", 22) val b = new Otus("Beepeli", 22) val c = new Otus("Aa" + "peli", 30-8) println(a==b) // false println(a==c) // true println(a=="kukamitaha") // falseHuom: Esimerkin equals-funktiossa on vasta myöhemmin opittavia asioita ja sen toteutus on myös puutteellinen!
Scalassa on toki myös oliosamuustestit, jotka ovat nimeltään eq ja ne. Siispä esimerkiksi seuraavat vertailut ovat false:
val a="he"; a+"llo" eq "hello" List(1, 2, 3) eq List(1, 2, 3)["he"+"llo" eq "hello" näkyy kuitenkin olevan true. Siispä jo kääntäjä näkyy osaavan evaluoida tuon String-vakioiden katenaation, mutta niin viisas kääntäjä ei ole, että osaisi tuon muuttujaan sijoitetun arvonkin oivaltaa. ;-]
Scalassa asia on sikäli kiinostava, että ohjelmoija voi sydämensä kyllyydestä ohjelmoida ikiomia operaattoreitaan.
Ideana on sopia asiat tyyliin: kaikki kertomerkillä (*) alkavat operaatiot (eli metodit) sitovat tiukemmin kuin mikään yhteenlaskumerkillä (+) alkava operaatio (eli metodi). Ja vain ensimmäinen merkki merkitsee. Siis vaikkapa kaikki *-merkillä alkavat operaatiot sitovat yhtä tiukasti eli samalla tiukkuudella.
Sitovuus ensimmäisen merkin perusteella tiukimmasta löysimpään:
muut kuin alla luetellut erikoismerkit * / % + - : = ! < > & ^ | kirjaimet kaikki sijoitusoperaatiot
Huom: Kuten aiemmin jo todettiin, :-merkkiin (kaksoispiste) päättyvät operaatiot assosioituvat oikealta vasemmalle. Kaikki muut operaatiot assosioituvat tuttuun tapaan vasemmalta oikealle.
0 max 5 5 0 min 5 0 -2.7 abs 2.7 -2.7 round -3 1.5 isInfinity false (1.0 / 0) isInfinity true 4 to 6 Range(4, 5, 6) "bob" capitalize "Bob" "robert" drop 2 "bert" ...(Tässä taas tarvitaan tuo import scala.language.postfixOps.)
Rikastuksia löytyy mm. luokista RichInt, RichChar, RichString, RichDouble RichBoolean. Katso Scala-API.