Muutettu viimeksi 18.3.2010 / Sivu luotu 9.3.2010 / [oppikirjan esimerkit] / [Scala]
Sivun sisältöä:
$ scala Welcome to Scala version 2.7.5final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_10). Type in expressions to have them evaluated. Type :help for more information. scala> 1 + 2 res0: Int = 3 scala> res0 * 3 res1: Int = 9Tulkki siis laittaa nuo arvot itse nimeämiinsä systeemivakioihin res0, res1, res2, ...
scala> println("Hello, world!") Hello, world!Metodikutsut ja muut algoritminpalaset suoritetaan sellaisinaan.
scala> val msg = "Hello, world!" msg: java.lang.String = Hello, world! scala> val msg2: java.lang.String = "Hello again, world!" msg2: java.lang.String = Hello again, world! scala> println(msg) Hello, world!Nimettyjä vakioita voi tietenkin määritellä itsekin. Mutta ne siis ovat vakioita:
scala> msg = "Goodbye cruel world!" <console>:5: error: reassignment to val msg = "Goodbye cruel world!" ^Toki muuttujiakin voi määritellä:
scala> var muu = 666 muu: Int = 666 scala> println(muu) 666 scala> muu = 14 muu: Int = 14 scala> println(muu) 14Rakenteen jäädessä kesken tulkki antaa uuden rivin:
scala> val multiLine = | "This is the next line." multiLine: java.lang.String = This is the next line.Tyypillisesti näin käy funktion määrittelyssä:
scala> def max(x: Int, y: Int): Int = { | if (x > y) x | else y | } max: (Int,Int)IntJos funktion runko muodostuu yhdestä lauseesta, aaltosulkeet saa jättää poiskin:
scala> def max2(x: Int, y: Int) = if (x > y) x else y max2: (Int,Int)Int scala> max(3, 5) res5: Int = 5Näiden kahden funktion tyyppi siis on (Int,Int)--->Int.
Huom: Funktion arvon tyyppi ilmaistaan otsikossa, ellei kääntäjä osaa sitä päätellä. Ja palautettavan arvon ilmaisemiseen riittää algoritmin suorituspolun viimeinen ilmaus, mitään returneja ei tarvita. Toisaalta return-lause on myös käytettävissä, jos halutaan algoritmiin useita erillisiä lopetuskohtia. Tätä ei kuitenkaan Scala-maailmassa pidetä tyylikkäänä eikä suotavana!
Huom: Koska "kaikella on arvo" ja arvo on lause-/lausekejonon viimeinen arvo, seuraavanlainen sivuvaikutuksilla pelleilykin on mahdollista:
scala> val x = {println("böö"); 78} böö x: Int = 78
Huom: Funktion muodollisten parametrien tyyppi annetaan aina, vaikka monissa muissa tilanteissa kääntäjä osaa päätellä tyypin.
"Void-metodin" tyyppi on Unit:
scala> def greet() = println("Hello, world!") greet: ()UnitParametrittoman funktion kutsussa tyhjä parametrilista ei ole tarpeen:
scala> greet Hello, world! scala> greet() Hello, world! scala> exit $
// Say hello to the first argument println("Hello, "+ args(0) +"!")Huom: Taulukon indeksit ovat kaarisulkeissa!
Tuttua ja turvallista:
var i = 0 while (i < args.length) { println(args(i)) i += 1 }Ja iffitkin peliin:
var i = 0 while (i < args.length) { if (i != 0) print(" ") print(args(i)) i += 1 } println()Huom: Scalassa ei ole operaatioita ++i ja i++. Ja hyvä niin! Ehtojen ympärillä on Javan tapaan oltava kaarisulkeet.
Skaalautuvalla Scalalla tuommoinen perinneohjelmointi toki onnistuu, ohjelmointi, jossa peräkkäin suoritettavin operaatioin muutetaan ja tutkitaan muuttujien arvoja eli ohjelman tilaa (state).
Mutta Scalalla hommia voi hoidella korkeammallakin abstraktiotasolla, vähän niin kuin funktionaalisemmin. Komentoriviparametrit voi tulostaa vaikka näin:
args.foreach(arg => println(arg))Näyttää siistiltä, mutta mitä tässä oikeastaan sanotaan?
args.foreach((arg: String) => println(arg))
(x: Int, y: Int) => x + yEikö alakin näyttää kahden muuttujan funktiolta, joka kuvaa argumenttinsa argumenttien summalle?
args.foreach(println)Tässä foreach-metodi saa parametrikseen osittain sovelletun funktion, println:n ilman parametria. foreach osaa sitten itse soveltaa tätä jokaiselle args-taulukon alkiolle. Tästä lisää myöhemmin.
args foreach printlnkoska foreach-metodikutsua voi käyttää myös infix-operaattorina.
for (arg <- args) println(arg)
Esimerkki: Laaditaan funktio, joka saa parametrina kaksi kokonaislukua ja funktion, joka kuvaa kaksi lukua kolmanneksi. Laadittava funktio soveltaa saamaansa funktiota parametrilukuihin:
def koristele(x: Int, y: Int, arvo: (Int, Int) => Int) = println("**** " + arvo(x, y) + " ****")Ja näin kätevästi sitä sitten voi käyttää:
koristele(5, 9, (x: Int, y: Int) => x + y) // **** 14 **** koristele(5, 9, (x: Int, y: Int) => x * y) // **** 45 **** def erotus(a: Int, b: Int) = a-b koristele(5, 9, erotus) // **** -4 ****Kuten näkyy, todellisena funktioparametrina voidaan antaa funktioliteraalien lisäksi toki myös nimettyjä funktioita.