You are on page 1of 21

Mark Lewis Scala Basics Zabeleke

01. Getting Started


na poetku piemo program HelloWorld, ekstenzija je .scala (za source kod Scala-e), kada se kompajlira dobija se
ekstenzija .class (kao kod Java-e, jer koristi JVM)
prvi put radimo iz Terminala
sve aplikacije u Scala-i se definiu kao objekti (eng. objects)
na vrhu kod Scala-e mogu da se nalaze ili object ili class-a ili trait
object je deklaracija koja kreira singletone objekat
unutar object-a staviemo main metodu
def je kljuna re za definisanje met ode
args je ime argumenata, koji je tip niza (eng. Array) String-ova
ova f-ja ne vraa nita, tj. vraa neto to nema informaciju, a to je tipa Unit
za razliku od Jave mesta imena argumenta, tj. parametra kao i njegovog tipa su promenjene
unutar te metode main emo odtampati tekst Hello World !
to je naa prva aplikacija

object Vezba {
def main(args: Array[String]) : Unit = {
println("Hello World!")
}
}

02.Beginning Eclipse
kod je isti kao malopre
Scala ima sledee komentare:
o single-line comment //
o multi-line comment /* */
o ScalaDoc comment /** */ - ScalaDoc tool - za kreiranje dokumentacije, kasnije se moe generiati HTML
iz ovog koda

03. Variables and types


Scala je staticly-typed jezik
i same promenljive imaju svoje vrednosti, a ne samo vrednosti koje sadre
deklarisaemo promenljive postoje 2 kljune rei za deklaraciju promenljivih:
o val nju ete koristiti vei deo vremena,
o val name = "Pat Cook"
Scala koristi type inference, a to znai da ukoliko preete miem preko promenljive name, videete da je tipa
String, to znai da smo postavili tip promenljive name na String
local type inference znai da e one pogledati u tu liniju koda i pokuae da skapiraju kojeg je promenljiva
tipa, tako da ne morate da je ekplicitno napiete
pored toga vi moete ekplicitno obezbediti tu promenljivu sa tipom
o val name:String = "Pat Cook"
pravimo jo jednu varijablu value i dodeljujemo joj vrednost 42, tako da je to tipa Integer
o val value = 42
druga kljuna re koju moete da koristite je var, takoe definiemo promenljivu tipa Int
o var age = 22
kao to smo ranije rekli ukoliko birate izmeu var i val, generalno bi trebalo da odaberete val
pitanje je ta je razlika ?

1
razlika je sposobnost da moete da dodelite vrednost
moemo da kaemo:
o age = 23
ili moemo da kaemo:
o a += 1
zato to age ima var deklaraciju, moe da bude ponovo dodeljeno drugom objektu, a to ne vai value, tj.
val
ukoliko pokuamo da uradimo sledee:
o value = 99
dobiemo greku
za val nije ba pravilno da se kae da su konstante, kada budemo radili nizove (eng. array) videete da iako
imamo val, moemo da promenimo (eng. to mutate) sadraj objekta, ali kada napravite val koji pokazuje na
objekat ono uvek pokazuje na isti objekat i vi ne moete da ponovo dodelite referencu na neki drugi
objekat promenljivoj val
sa druge strane sa var-om to moete da uradite
razlog zato su val poeljne jeste pojednostavljivanje logike, lake je u tom sluaju razmiljati o programu
vidimo da se tipovi navode velikim slovom, to u sutini znai klasa u Scala-i, kao npr. String, Int, Double, Char,
Boolean, Unit (tip koji ne predstavlja nikakvu informaciju)
otvorena i zatvorena zagrada jedna pored druge je nain da kreirate Unit tip podatka
o val nonUseful = ()
postoji jo jedan vaan tip to je tuple tip n-torka ili torka !,
unutar zagrada stavite vrednosti, odvojene zarezima i to je tuple, u ovom sluaju to je promenljiva t
o val t = (1, 2.7, "hi there")
ovo je jednostavan nain da napravite mali objekat, koji kombinuje nekoliko tipova
sada ukoliko elite da izvuete vrednosti odatle, jednostavan nain je sledei:
o val (a, b, c) = t
drugi nain za izvlaenje vrednosti iz tuple-a su metode: _1, _2 i _3 (eng. underscore methods)
o println(t._1) ovo e odtampati broj 1 kao prvi element
primetite da su ove underscore metode uglavnom one-reference (1 reference)
tuple 1 index, to znai da njegov indeks poinje od 1 a ne od 0 (to je zbog istorijskih razloga)

04. String Interpolation


imamo 2 promenljive: name i age
moemo da imamo neku promenljivu message koja kombinuje ove 2 stvari
jedan od naina je:
o val message = name + " is " + age + " years old."
ovaj kod sada pokazuje da smo iskoristili + znak da bi smo uradili nadovezivanje stringova i on povezuje sve
stvari u jednu
ovo je use-case za String Interpolation
alternativni nain za ovu poruku (eng. message) je:
o val message2 = s"$name is $age years old."
dakle, pre samog stringa stavljamo karakter s, a pre promenljive stavimo znak $
postoji jo jedna mogunost kod interpolacije String-ova, ukoliko elim da dodam sloeniji izraz, npr elim da
prikaem drugi element u tuple-u i ispiem
o val str = s"The second element of t is $t._2."
primetite da se ovo kompajlira, ali ne radi ono to elimo, ve za t dobijamo ceo tuple, stoga kod sloenijih
izraza staviemo vitiaste zagrade:
val str = s"The second element of t is ${t._2}."
lake je raditi sa kompaktnijom formom koju prua Interpolacija String-ova

2
5. Statements and Expressions
Scala je funkcionalni jezik na mnogo naina
jedan od tih aspekata je da gotovo sve to nije deklaracija u Scala-i je izraz (eng. Expression)
ta to znai ?
naredba je kod koji govori jeziku da uradi neto, ali ne proizvodi vrednost
naredbe imaju efekta, ali ne vraaju vrednost sa kojom radite
sa druge strane izraz (eng. expression) je neto to proizvodi vrednost, npr. ovo je izraz:
o name + " is " + age + " years old."
ne samo to vraa vrednost izraz ima i tip koji je povezan sa njim, u ovom sluaju to je String
najjednostavniji izrazi su literali, npr. vrednost 22, mi moemo iskombinovati literale sa operatorima, kao npr. sa +
o (age + 1)
takoe izraz moe da bude i:
o value+age
iako ovo izgleda kao kod u nekom drugom programskom jeziku kod Scala-a ima dodatno znaenje
znak + nije ubaen u jezik, ve je deo biblioteke, tj. to je metoda koja je definisana nad Integer tipom, tako da
gorepomenuti izraz moe da se napie:
o value.+(age)
generalno, vi moete uzeti bilo koji operator koji prihvata jedan argument i napisati ga u inline formatu, koji smo
videli:
o value + age
takoe Integer tipa ima metodu koja se zove min (koja vraa manju vrednost od age), tako da moete da kaete:
o value.min(age)
, ali zbog ovog generalnog pravila argument moe biti koripen u infix notaciji, tako da moete napisati sledee:
o value min age
u Scala-i == radi poveru po jednakosti, tako da e sledei izraz biti true:
o name == "Pat Cook"
jo jedan dodatak, jeste da moete raditi jeste multipliciranje stringa mnoenjem sa integer-om, gde se u tom
sluaju string ponavlja nekoliko puta
o "Pat Cook" * 5
sada emo otvoriti REPL Repeat Evaluate Print Loop
sada moemo ukucati izraze i vidimo da nam oni daju vrednost, takoe i njihov tip
o scala> 4 + 5
o res0: Int = 9
ta e se desiti kada saberem 4 i 5.0 ? Iskombinovae se u double.
o scala> 4 + 5.0
o res1: Double = 9.0
ta je sada sa deljenjem ?
o scala> 9 / 5
o res2: Int = 1
obe vrednosti su integer, tako da je to deljenje Integer-a i postoji samo jedna 5 koju moete da izvuete iz 9
ukoliko elite ostatak pri deljenju mote iskorisiti modulo operator
o scala> 9 % 5
o res3: Int = 4
obzirom da su tipovi bitni vidimo sada kada broj 9 podelimo sa 5.0, videemo da dobijamo decimalni kolinik
o scala> 9 / 5.0
o res5: Double = 1.8
za logike operacije Scala koristi isti stil kao i C ili Java, tako da ako imam 2 boolean vrednosti: true i true i
sprovedem operaciju logikog I, dobiemo true
o scala> true && true
o res6: Boolean = true

3
6. Lambda Expressions
u Scala-i simbol za lambda izraze je znak => (eng. rocket)
ideja iza Lambda izraza je kratak literal izraz koji definie funkciju, koji tipino nije predugaak
npr. moemo da definiemo funkciju za kvadriranje:
ukoliko izraz zapiemo na sledei nain:
o val square = x => x * x
Scala e prijaviti greku, znak rakete (eng. rocket) => nam pokazuje da imamo argument sa leve strane, tj. x i on
ide u neki izraz sa druge strane, tako da x ide u x na kvadrat
moda postavljate pitanje zato ne bih uradio:
o def square(x: Double):Double = x * x
tehniki ovaj deo sa def je metoda objekta Hello World, nije stvarno funkcija
takoe postoji vei broj mesta u Scala-i gde emo pisati funkcije, a neemo im dati ime, ve e biti neto to je
malo, koristimo ih jednom, nema potrebe da ih koristimo vie puta i pisanje def sa njih je malo teko
ispostavlja se da moete da koristite metode na mestima koja imaju prosleene funkcije, tako da razlika meu
njima nije toliko jaka
zato u gornjem kodu, Scala nije srena:
o val square = x => x * x
problem je tip, Scali je potrebno da zna kojeg je tipa ulazni argument sa leve strane, jedan nain da to popravimo
je sledei:
o val square = (x: Double) => x * x
dakle sa leve strane je lista argumenata za funkciju, a sa leve je telo funkcije
u ovom sluaju Scala moe da zakljui kojeg je tipa
takoe, ovo moete pozvati kao bilo koju funkciju
o println(square(23))
drugi nain je sledei:
o val square:Double => Double = x => x * x
postoji i alternativna sintaksa koju je mogue upotrebiti, jer radi samo u odreenim situacijama, a to je
underscore sintaksa (_)
to emo prikazati na primeru funkcije koja prihvata argument i mnoi ga 2 puta, tj. duplira, umesto da piemo
sledei kod:
o val twice: Double => Double = x => x * 2
ukoliko se svaki argument samo pojavljuje jednom, tada moete napisati sledee:
o val twice: Double => Double = _ * 2
dakle, moemo da napiemo _ * 2, to se ita neto (eng. something) * 2, _ je samo placeholder za nas
ova skraenica je veoma zgodna za mnogo stvari
esto se koristi kod poreenja, npr. funkcija lt less then (manje jednako), prihvata 2 broja Double i vraa
Boolean, to moemo zapisati:
o val lt: (Double, Double) => Boolean = (x, y) => x < y
a u veini situacija to moemo zapisati:
o val lt: (Double, Double) => Boolean = _ < _

7. if and while
izbrojaemo do 10 preko while petlje
o var i = 0
o while (i < 10) {
o println(i)
o i += 1
o }
ne podrava sintaksu i ++
ne postoji prefix i posfix increment
while je pre-check petlja, to znai da uslov proverava pre nego to ue u petlju

4
sa druge strane do while petlja je post-check petlja, to znai da uslov proverava nakon izvrenja petlje
o var i = 0
o do {
o println(i)
o i += 1
o } while (i < 10)
kod do while-a telo se izvrava najmanje jednom
ta je sa if-om ?
if izgleda kao u drugim jezicima, imamo age u ovom kodu
moemo da napiemo neto ovakvo
o if (age < 18) {
o println("No admittance.")
o } else {
o println("Come on in.")
o }
ovo je nain upotrebe if naredbe, kao i u ostalim programskim jezicima u obliku naredbe (eng. statement)
dakle, ukoliko je uslov taan izvrava se blok u if-u u suprotnom izvrava se blok komandu u else-u
u Scala jeziku if je izraz (eng. expression), tako da ovo moe da se uradi na nekoliko drugih naina
jedan od naina je preko deklarisanja promenljive, a ta promenljiva e biti string
nakon toga moemo da odtampamo tu promenljivu:
o val response = if (age < 18) {
o "No admittance."
o } else {
o "Come on in."
o }
o println(response)
sada emo zapisati ovo na jo jedan nain, gde emo samo da uzmemo izraz i da ga iskoristimo u println
o println(if (age < 18) "No admittance." else "Come on in.")
jedan od problema koji se moe javiti jeste ukoliko koristite if kao izraz (eng. expression) i ukoliko imate if deo, a
pri tome nemate else, izraz e implicitno da vrati tip podatka Unit, to nije korisno
npr. ukoliko imate sledei kod:
o val a = if(true) "hi" else 5
ovo ne bi bilo previe korisno, jer ili mogu da vratim hi ili 5, gde je jedno String a drugo je Int, ako moe da bude
String i ako moe da bude Int ta je onda promenljiva a, kojeg je tipa ? Promenljiva a je tipa any.
any nije toliko korisna, tako da kada koristite if naredbu kao izraz grane if-a i elsa trebalo bi da vraaju isti tip
podatka

8. for Loops / Comprehensions


napiimo sada for petlju koja izbrojava od 1 do 10, ova strelica <- se najee ita kao u (eng. in)
o for(i <- 1 to 10) {
o println(i)
o }
ukoliko sada elim da moja petlja ispisuje od 0 do 9, tada mogu da promenim malo ovaj kod:
o for(i <- 0 to 9) {
o println(i)
o }
ili mogu da iskoritim naredbu until:
o for(i <- 0 until 10) {
o println(i)
o }
to i until su zapravo metode nad Int, i oni proizvode tzv. ranges
ono to je u Scala-i for petlja, ona je veoma slina foreach petlji u Java-i, jer uvek prolazi kroz kolekciju

5
dakle kod Scale u for petlju se stavi generator (eng. generator), tj. neto to dolazi iz kolekcije
ispada da pored ovoga, moete imati i mnogo vie
mogu da dodam uslov u for petlji tako da tampa samo one koje su deljivi sa 3 ili sa 5
o for(i <- 1 until 10; if i % 3 == 0 || i % 5 == 0) {
o println(i)
o }
pored toga moemo dodati viestruke generatore, to je slino ugnjedavanju for petlje
o for(i <- 1 until 10; if i % 3 == 0 || i % 5 == 0; j <- 'a' to 'c') {
o println(i + " " + j)
o }

sada emo dodati jedan uslov ili izraz u petlju, npr mogu dodati izraz i nakon toga koristiti promenljivu unutar
petlje
o var sqr = i * i
kod je:
o for(i <- 1 until 10; if i % 3 == 0 || i % 5 == 0; sqr = i * i; j <- 'a' to 'c') {
o println(i + " " + j)
o }
za ovaj kod iznad postoji alternativna sintaksa koja se koristi dosta, prvo promenimo obine zagrade sa vitiastim,
zatim vie nam nisu potrebni taka-zarez ;, :
o for {
o i <- 1 until 10
o if i % 3 == 0 || i % 5 == 0
o sqr = i * i
o j <- 'a' to 'c'
o }{
o println(i + " " + j)
o }
na ovaj nain se for upotrebljava kao naredba (eng. stamenent), dakle nita nam ne vraa
da bi ste koristili for kao izraz (eng. expression) potrebno je staviti kljunu re yield nakon sekcije for
o for {
o i <- 1 until 10
o if i % 3 == 0 || i % 5 == 0
o sqr = i * i
o j <- 'a' to 'c'
o } yield {
o println(i + " " + j)
o }
u ovom trenutku for e da yield-uje neto neiteresantno zato to println vraa Unit tip podatka, tako da emo
umesto println, napraviti tuple i to upisati u promenljivu stuff, kao u sledeem kodu:
o val stuff = for {
o i <- 1 until 10
o if i % 3 == 0 || i % 5 == 0
o sqr = i * i
o j <- 'a' to 'c'
o } yield {
o i -> j
o }
a nakon toga moemo da odtampamo taj tuple
o println(stuff)
vidimo da dobijemo tip podatka Vector, koji sadri sve tuple-ove kao kombinaciju
o Vector((3,a), (3,b), (3,c), (5,a), (5,b), (5,c), (6,a), (6,b), (6,c), (9,a), (9,b), (9,c))

6
9. match Expression
veina jezika ima neku formu viestruke selekcije, npr. u Java-i imate switch naredbu
match izraz (eng. expression) je mnogo monija nego obina swicth naredba u Java-i
ono to ini match izraze mone u Scala-i jeste to to preko njih moe da se uradi pattern matching
osnovna sintaksa jeste da imamo izraz odreenog tipa, kod nas emo izgraditi tuple koji ima 2 vrednosti
kreiraeno petlju koja ide od 1 do 20
radimo fizzbuzz problem: ako je broj deljiv sa 3 ispisujemo fizz, ako je deljiv sa 5 ispisujemo buzz, a ako vai i
jedno i drugo ispisujemo fizzbuzz, ako nije nita od toga potrebno je da vratite isti broj:
o val fizzbuzz = for( i <-1 to 20) yield {
o if (i % 3 == 0 && i % 5 == 0) "fizzbuzz"
o else if (i % 3 == 0) "fizz" ...
o }
o }
ovu logiku ne elimo da radimo na ovaj nain, ve elimo da je uradimo preko match naredbe
postavljamo onoliko puta vitiastih zagrada koliko imamo razliitih sluajeva, tj. case-ova
u ovoj situaciji sam zainteresovan za ostatak pri deljenju sa 3 i ostatak pri deljenju sa 5
jedan case je (0, 0) dakle case prati patter koji moe da bude prosta vrednost, takoe moe da sadri
promenljive, u ovom case-u nam je potrebno da za obe promenljive bude ispunjen uslov, tako da tu ispiemo
fizzbuzz
drugi case je (0, _) dakle deljiv je sa 3, ali nije deljiv sa 5 i tada e se ispisati fizz, donja crta (eng. underscore)
znai bilo ta (eng. anything)
takoe imamo case u kojem je prva vrednost bilo ta, a druga vrednost je 0, tj. (_, 0) i u tom sluaju e ispisati
buzz
jo nam ostaje case kada nita nije od ovoga navedenog, gde samo elimo da ispiemo broj, i tamo emo staviti i
o val fizzbuzz = for( i <-1 to 20) yield {
o (i % 3, i % 5) match {
o case(0, 0) => "fizzbuzz"
o case(0, _) => "fizz"
o case(_, 0) => "buzz"
o case _ => i
o }
o }
ukoliko samo vratim i, tip u promenljivoj fizzbuzz je sekvenca tipova Any, to nam nije korisno
i zbog tog razloga da bi svi elementi ove kolekcije bili string i emo konverovati u string, preko linije
o case _ => i.toString
kod match-a elimo da svi razliiti sluajevi (eng. case) imaju isti tip, tako da dobijete malo korisniju kolekciju
kada odtampamo fizzbuzz promenljivu preko naredbe println dobijamo sledee:
o Vector(1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz, 16, 17, fizz, 19, buzz)

10.try-catch
try-catch je malo drugaije u Scala-i u odnosu na ostale programske jezike, a to je da je to izraz u Scala-i
dakle imamo string i elimo da ga konvertujemo u integer
u Scala-i moete pozvati toInt metodu i ona e vam vratiti integer
o val str1 = "123"
o val num = str1.toInt
ukoliko String nije odgovarajui Integer, npr. 123a, a mi to pokrenemo, nastae exception
Exception in thread "main" java.lang.NumberFormatException: For input string: "123a"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
at scala.collection.immutable.StringOps.toInt(StringOps.scala:29)
at basics.Vezba$.main(Vezba.scala:97)
7
at basics.Vezba.main(Vezba.scala)
potrebno je da u kodu to identifikujem i da se pozabavim time na neki nain
elim da namesti da ukoliko je u string-u broj tada da on bude dodeljen promenljivoj, a u suprotnom da bude 0
postavljamo kod koji moda ima problema u try deo
a catch deo nam izgleda kao match, ima vei broj pattern-a, preko vie case-eva koji se jo nazivaju i parcijalne
funkcije (eng. partial function)
sada elim da uhvatim izuzetak, koji znam da obradim, dakle u ovom sluaju FormatException
tako da NumberFormatException evaluiramo sa 0
o val str1 = "123a"
o val num = try {
o str1.toInt
o } catch {
o case ex:NumberFormatException => 0
o }
o println(num)
dakle, ovaj kod radi ono to je potrebno
to je osnovna ideja iza try, catch-a

11. Declarations and Scope


scope, tj. oblast vaenja u Scali je definisan preko vitiastih zagrada
vidimo da object ima svoj scope, kao main metoda
za sada ste videli 4 tipa deklaracije i svaka od te 4 deklaracije ima kljunu re koja ide sa deklaracijom:
o object singleton objekat
o val - promenljive
o var - promenljive
o def metode
o kao dodatak imamo class i trait
u Scala-i prvo ide kljuna rea za deklaraciju, a nakon toga ime, npr. val t, naravno to malo zavisi u odnosnu
na to ta definiete
kada neto definiete to moe da ivi unutar odreene sekcije u programu i ivi od take deklaracije do kraja
vitiaste zagrade3
argumenti funkcije imaju scope, kroz celo telo funkcije, tj. metode
ukoliko promenljivu definiemo unutar vitiastih zagrada, njena oblast vaenja, tj. scope je samo unutar tih
zagrada

12. Libraries and Standard Input


za sada smo radili sa metodom println koja je ispisivala na sistemski izlaz, a sada emo raditi sa metodom koja
moe da prihvati sa sistemskog ulaza, a za to nam je potrebna biblioteka (eng. library)
konkretno za ovu situaciju nam je potreban paket io (input output) i unutra objekat StdIn
prvo emo pitati korisnika da unese svoje ime (eng. name)
nakon toga emo pitati korisnika za godine da ih unese
ono to smo trenutno iskucali je ???
package basics

object Biblioteke {
def main(args: Array[String]) : Unit = {
println("What is your name ?")
???
println("How old are you ?")
???
}
}
??? se kompajliraju, to je deo Scala biblioteke, to je expression koji obezbeuje neto to je tipa Nothing

8
ovaj ??? moete staviti bilo gde u program ukoliko ne znate ta ete da radite, ono je ak manje i od Unit koje
ipak vraa neto
ukoliko se ikada pokrene ovaj kod dobiete NotImplementedError exception
postoji readLine() metoda koja prihvata ulaz sa tastature
ukoliko vidimo ta metoda se nalazi u io, pa u objektu StdIn
za age uradimo metodu readInt()
kod sada izgleda:
package basics

import scala.io.StdIn._

object Biblioteke {
def main(args: Array[String]) : Unit = {
println("What is your name ?")
val name = readLine()
println("How old are you ?")
val age = readInt()
}
}

13. Arrays and Lists


Scala ima dosta kolekcija i svi su dostupni unutar paketa scala.collection
sada emo iskoristiti REPL

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_112).
Type in expressions for evaluation. Or try :help.

scala>

niz (eng. array) moete izgraditi tako to ete kucati kljunu re Array, a u zagradama ete dati vrednosti
elementima niza
scala> Array(9, 4, 7, 2, 5)
res0: Array[Int] = Array(9, 4, 7, 2, 5)

na isti nain moete izgraditi listu


scala> List('a', 'j', 'y')
res1: List[Char] = List(a, j, y)

postoje 2 razlike izmeu nizova i listi:


jedna od njih je mutability
da bi ste izvukli vrednosti iz ovih stvari, koristiemo imena za niz res0, a za listu res1
preko indeksa moete vratiti element i iz liste i iz niza
scala> res0(2)
res2: Int = 7

scala> res1(2)
res3: Char = y

i liste i nizovi su zero-indexed


prva razlika izmeu njih jeste da je niz mutable, a lista nije
ta to znai ?
ja mogu treem elementu niza dodeliti vrednost 99
scala> res0(2) = 99

9
ako sada pogledam res0, vidimo da je niz promenjen
scala> res0
res5: Array[Int] = Array(9, 4, 99, 2, 5)

izgradimo sada novi niz Integer-a i treem elementu niza dodelimo vrednost 99
scala> val arr = Array(7, 5, 2, 89, 23)
arr: Array[Int] = Array(7, 5, 2, 89, 23)

scala> arr(2) = 99
i sada kada pogledamo arr vidimo sledee:
scala> arr
res7: Array[Int] = Array(7, 5, 99, 89, 23)

vidimo da je kada smo definisali niz arr, to je val deklaracija


kada smo priali o val i razlici izmeu val i var, to je da ne moete da im dodelite vrednost
istina je da ja ne mogu da kaem da promenljivoj arr dodelim jo jedan niz:

scala> arr = Array(1, 2, 3)


<console>:12: error: reassignment to val
arr = Array(1, 2, 3)
^
dakle ovo ne funkcionie, zato to ne mogu da ponovo dodelim vrednost val
ali sam objekat niz Array je mutable

arr e uvek pokazivati na isti niz, ali sadraj tog niza moe da se promeni
kod lista to nije sluaj, ako kaemo sledee, dobijamo greku:
scala> res1(2) = 'z'
<console>:13: error: value update is not a member of List[Char]
res1(2) = 'z'
^
dakle, ne moete aurirati vrednosti unutar liste
lista kada se jednom kreira kompletno je immutable
funkcionalni jezici imaju tendenciju da koriste immutable strukture podataka
kada kreiramo niz moemo da promenimo vrednosti unutar niza, ali ne moemo efikasno da promenimo veliinu
niza
kod lista moemo veoma efikasno dodati element na poetak liste
dodavanje na kraj nije efikasno, ali dodavanje na poetak jeste:
scala> res1
res9: List[Char] = List(a, j, y)

scala> 'b' :: res1


res10: List[Char] = List(b, a, j, y)
ovo nam je zapravo dalo novu listu, res1 se nije promenilo, dok je res11 nova lista, koja ukljuuje ceo sadraj od
res1
ukoliko mi je potrebno neto to ima varijabilnu duinu, tada u koristiti liste
ukoliko mi je potrebno neto to ima fiksnu duinu, a potrebna mi je mutabilnost koristiu niz
ukoliko odaberete neto iz nekog razloga i odluite u nekom trenutku da vam je potrebno neto drugo moete
iskoristiti metode:
nad listom moete pozvati metodu toArray
nad nizom moete pozvati metodu toList
scala> res1.toArray
res11: Array[Char] = Array(a, j, y)

scala> res0.toList

10
res12: List[Int] = List(9, 4, 99, 2, 5)

dakle, moete ih jednostavno konvertovati jedne u druge

14. fill and tabulate


postoje metode fill i tabulate koje nam koriste da napravimo vee nizove i liste
iskoristiemo metodu fill nad Array-om, koja ima 100 vrednosti koje e sve biti 0
scala> Array.fill(100)(0)
res13: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
ukoliko elim da mi lista bude popunjena sa 100 proizvoljnih brojeva, moemo iskoristiti math.random, math.
objekat ima gomilu pomonih metoda
scala> List.fill(100)(math.random)
res14: List[Double] = List(0.6264917274799423, 0.6852192035840377, 0.6273637262863272,
0.6733079291443371, 0.7144400638997207, 0.4745022292560467, 0.7278103408630915,
0.5782706268045624, 0.7543124026583569, 0.40459718514497567, 0.9795539726306467,
0.8843641672008201, 0.4603390480331171, 0.5132476543616518
i tako dobijam gomilu proizvoljnih vrednosti izmeu 0 i 1
fill je curry-ed metoda, uzima 2 argumenta kao odvojene liste
drugi element fill metode je izraz koji se evaluira i dokle god se skladite vrednosti
kod fill-a nemate pojma gde se nalazite u kolekciji, uzmimo sledei primer gde izgraujemo listu sa 5 unosa sa
standardnog ulaza
scala> List.fill(5)(io.StdIn.readLine)
abc
def
rty
is this
re
res16: List[String] = List(abc, def, rty, is this, re)
iako ovaj izraz moe biti evaluiran mnogo broja puta, fill ne obezbeuje informaciju gde se nalazimo
npr. ukoliko elim da imam niz gde je svaki element jednak njegovom kvadratu indeksa, tada mogu da koristim
tabulate, tada mogu da koristim funkciju kao drugi argument prihvata indeks
scala> Array.tabulate(10)(i => i * i)
res17: Array[Int] = Array(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)
zao to ima 10 elemenata, kree od 0 i ide do 9, dakle to je 10 i obezbeuje kvadrate za svaku od vrednosti
indeksa
dakle, ukoliko elite izgradite vee nizove ili liste, nain na koji ete tipino da uradite, jeste upotrebom fill i
tabulate
kod nizova moete korisiti i sintaksu koja je dola iz Java-e, kada iskoristite ovo nad nizom od 20 lanova dobijate
sledee
scala> new Array[Int](20)
res18: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
raditi ovo sa listom nije ba pametno zato to je lista immutable
obino se ovo ovako ne radi, jer kada bih recimo koristio tip podatka string dobio bih 20 null vrednosti

15. Range
nisu samo Array i List sequence tipovi, ve to je i Range koji smo videli u upotrebi ve
kada smo priali o for petlji koja prolazi kroz kolekciju kucali smo sledee
scala> 1 to 10
res19: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
dakle 1 to 10, proizvodi range
11
dve metode su definisane za integer, jedna poziva 1 to 10
scala> 1.to(10)
res20: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
moete korisiti to i until, to ukljuuje granicu tj. inkluzivno je, dok until ne ukljuuje granicu tj.
ekskluzivno je
pored toga to ovo radimo a integer-ima to moemo da uradimo sa karakterima
scala> 'a' to 'z'
res21: scala.collection.immutable.NumericRange.Inclusive[Char] = NumericRange(a, b, c, d, e, f, g,
h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)
ta na primer ukoliko od 1 do 10 elim da brojim po 2
scala> 1 to 10 by 2
res22: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)
na slian nain mogu da kaem od a do z po 3
scala> 'a' to 'z' by 3
res23: scala.collection.immutable.NumericRange[Char] = NumericRange(a, d, g, j, m, p, s, v, y)
ukoliko koristite double i ukoliko napiete:
scala> 1.0 to 10.0
res24: Range.Partial[Double,scala.collection.immutable.NumericRange[Double]] =
scala.collection.immutable.Range$Partial@2c332922
ovo nije dobro napisano dok ne koristite by
scala> 1.0 to 10.0 by 1.0
res25: scala.collection.immutable.NumericRange[Double] = NumericRange(1.0, 2.0, 3.0, 4.0, 5.0,
6.0, 7.0, 8.0, 9.0, 10.0)
kod Range-ova takoe moete da brojite unazad, npr. 10 to 1
scala> 10 to 1
res26: scala.collection.immutable.Range.Inclusive = Range()
vidimo da u sebi nema nita, dok ne definiemo
scala> 10 to 1 by -1
res27: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

16. Basic Sequence Methods


snaga Scala programskog jezika jeste u metodama koje kolekcije imaju
sada emo definisati niz (eng. array), a ove metode koje prolazimo podjednako rade i sa nizovima i sa listama
(eng. lists)
nastaviemo sa radom u REPL modu
scala> val a = Array(6, 9, 1, 5, 8, 2, 3, 4)
a: Array[Int] = Array(6, 9, 1, 5, 8, 2, 3, 4)
postoji metoda drop koja uklanja odreenji broj elemenata
scala> a.drop(2)
res28: Array[Int] = Array(1, 5, 8, 2, 3, 4)
ta ukoliko ne elim da uklonim elemente sa poetka, ve sa kraja ?
scala> a.dropRight(2)
res29: Array[Int] = Array(6, 9, 1, 5, 8, 2)
sa metodom dropRight smo uklonili 2 elementa sa kraja
ukoliko elim samo prvi element koji se naziva head, mogu da napiem:
scala> a.head
res30: Int = 6
ukoliko elim sve osim prvog elementa to se zove tail, mogu da napiem:
scala> a.tail
res31: Array[Int] = Array(9, 1, 5, 8, 2, 3, 4)
pored toga moete zatraiti poslednji element
scala> a.last
res32: Int = 4
12
takoe moete duinu, preko length
scala> a.length
res33: Int = 8
pored toga, poslednji element sam mogao da dobijem i preko length
scala> a(a.length - 1)
res34: Int = 4
pogledajmo sada metodu split, koja zapravo vraa tuple sastavljenu od 2 niza
scala> a.splitAt(3)
res0: (Array[Int], Array[Int]) = (Array(6, 9, 1),Array(5, 8, 2, 3, 4))
ukoliko elim da preuzmem prva 3 elementa, to mogu sa metodom take
scala> a.take(3)
res1: Array[Int] = Array(6, 9, 1)
ukoliko elim da preuzemem poslednja 3 elementa mogu da iskoristim takeRight
scala> a.takeRight(3)
res2: Array[Int] = Array(2, 3, 4)
postoje jo 2 metode koje su malo sloenije:
jedna od njih je slice, koja prihvata 2 argumenta, poetni indeks i krajnji indeks
scala> a.slice(2, 5)
res3: Array[Int] = Array(1, 5, 8)
vidimo da smo preuzeli elemente sa indeksima 2, 3 i 4, a nismo preuzeli element sa indeksom 5
drugi element kod metode slice je ekskluzivna granica, to znai da ne obuhvata taj indeks
metoda patch slui za izmenu jednog segmenta vae kolekcije
scala> a.patch(3, Array(88, 89), 3)
res4: Array[Int] = Array(6, 9, 1, 88, 89, 3, 4)
patch prihvata indeks sa kojim elite da krenete u izmenu segmenta vae kolekcije, tako da ukoliko elim da
izmenim 5, 8 i 2, to onda poinje sa indeksom 3, gde nakon toga stavite argument sa kojim elite da zamenite
kod nas je Array(88, 89), a elim da zamenim 3 elementa to su 5, 8 i 2 (duina 3)
dakle 5, 8 i 2 su zamenjeni sa 88 i 89
postoji par metoda koje omoguavaju ponaanje kao skupovi, tj. set-ovi
jedna od njih je diff metoda koja uzima sve elemente osnovnog niza koji se ne nalaze u argumentu koji je niz
scala> a.diff(Array(1, 2, 3, 4))
res5: Array[Int] = Array(6, 9, 5, 8)
postoji takoe metoda distinct, npr. ako imam niz:
scala> Array(1, 2, 7, 7, 4, 3, 7, 1, 1).distinct
res6: Array[Int] = Array(1, 2, 7, 4, 3)
vidimo da se svodi na niz gde se svaki element pojavljuje samo jednom, kako je pronaen
takoe postoji i presek (eng. intersection)
scala> a.intersect(List(4, 5, 6, 7))
res8: Array[Int] = Array(6, 5, 4)
takoe moemo da radimo uniju, gde u tom sluaju imamo oba
scala> a.union(Array(1, 2, 11, 12))
res9: Array[Int] = Array(6, 9, 1, 5, 8, 2, 3, 4, 1, 2, 11, 12)
neke druge metode koje su zgodne za upotrebu, a mogu da rade samo sa odreenim tipovima kao to su npr.
Integer-i, npr. kao to su min i max:
scala> a.min
res10: Int = 1

scala> a.max
res11: Int = 9
pored toga imamo sumu i proizvod
scala> a.sum
res14: Int = 38

scala> a.product
res15: Int = 51840
13
takoe imamo sorted, koji vraa novu kolekciju
scala> a.sorted
res16: Array[Int] = Array(1, 2, 3, 4, 5, 6, 8, 9)
takoe imamo mkString, koja ima 3 razliite verzije
prva napravi stringove od svih vrednosti i zalepi ih u jednu
scala> a.mkString
res17: String = 69158234
druga varijanta je recimo da imamo zarez (, ) izmeu njih
scala> a.mkString(", ")
res18: String = 6, 9, 1, 5, 8, 2, 3, 4
takoe moemo da im prosledimo 3 argumenta, prvi je neto to elimo da stavimo ispred, nakon toga stavljam
delimiter, a nakon toga stavljam strong koji je posle
scala> a.mkString("[", ", ", "]")
res19: String = [6, 9, 1, 5, 8, 2, 3, 4]
poslednje 2 metode koje elim da pogledam ovde su veoma korisne
jedna od njih se zove zip, elim da uzmem moj orginalni niz i da ga zipp-ujem sa jo nekim nizom
scala> a.zip('a' to 'z')
res20: Array[(Int, Char)] = Array((6,a), (9,b), (1,c), (5,d), (8,e), (2,f), (3,g), (4,h))
dakle uzima se prvi broj, kombinuje sa sa a i vraa nam se tuple, prvi sa prvim, drugi sa drugim, i td
druga metoda se zove zipWithIndex i to je zapravo raenje zip metode, u kojoj se koriste indexi orginalne
kolekcije
scala> a.zipWithIndex
res21: Array[(Int, Int)] = Array((6,0), (9,1), (1,2), (5,3), (8,4), (2,5), (3,6), (4,7))

17. Higher-Order Sequence Methods


jedna od kljunih karakteristika funkcionalnog programiranja jeste mogunost prosleivanja funkcija
moete tretirati funkcije kao bilo koje druge vrednosti i moete ih prosleivati drugim funkcijama i metodama, koje
mogu da vam ih vrate
kada funkcija prihvata drugu funkciju kao argument ili je vraa ona se zove Higher-Order function, u ovom sluaju
emo da radimo sa Higher-Order metodama
dakle ovim metodama prosleujete funkcije, a te funkcije definiu ono to se deava
Higher-Order metode su veoma mone, a pogotovo 3 sa kojima elim da zaponem
prva najmanje interesantna sa kojom elim da zaponem je foreach, ono to foreach radi jeste da izvrava
funkciju nad svakim elementom kolekcije, npr. elim da vidim sve vrednosti koje se nalaze u tom nizu
scala> a.foreach(println)
6
9
1
5
8
2
3
4
druge 2 vane metode su map i filter i one vraaju vrednosti
umesto da koristite gomila petlji da vam sraunavaju neto nad kolekcijom vi moete da koristite map i filter
ideja map-a je da map prolazi i primenjuje funkciju nad svakim elementom, stim da ta funkcija vam vraa
rezultat i koji god da je rezultat on se ubacuje u novu kolekciju
npr. ja mogu da pomnoim sve elemente u naem nizu sa 2
scala> a.map(_ * 2)
res24: Array[Int] = Array(12, 18, 2, 10, 16, 4, 6, 8)
ukoliko se seate ova donja crta je skraenica za lambda sintaksu, tako da smo isti rezultat mogli da dobijemo
sledeim kodom
scala> a.map(x => x * 2)
14
res25: Array[Int] = Array(12, 18, 2, 10, 16, 4, 6, 8)
dakle sintaksa sa donjom crtom, otprilike moe da se ita kao ja u da mapiram sve elemente od a sa neim
pomnoeno sa 2, to zapravo duplira sve vrednosti
svaki put kada razmiljate da je potrebno neto da sraunate za sve elemente kolekcije trebalo bi da
razmiljate o map funckiji
poslednja od 3 najvanije High-Order metode je filter
svrha filter-a je isto da prihvati funkciju a potrebno je da vrati boolean, tako npr. moda elim sve elemente
koji su manji od 5
scala> a.filter(_ < 5)
res26: Array[Int] = Array(1, 2, 3, 4)
takoe mogu da uradim filter i da dobijem parne vrednosti
scala> a.filter(_ % 2 == 0)
res27: Array[Int] = Array(6, 8, 2, 4)
ima jo dosta funkcija, a ima i onih poznatijih kao predikat to je funkcija koja vraa boolean vrednost, npr. filter
je jedna od njih
sada ne elim da vidim parne vrednosti, ve elim da ih prebrojim
scala> a.count(_ % 2 == 0)
res28: Int = 4
takoe moemo proveriti konstrukcije, tipa da li neto vai za sve ili vai za neke od elemenata
scala> a.exists(_ < 5)
res30: Boolean = true
ukoliko elim da vidim da li ima veih od 10, moja kolekcija nema takve, pa e rezultat biti false
scala> a.exists(_ > 10)
res31: Boolean = false
takoe postoji metoda forall, koja vraa boolean i govori da li je neki predikat true za sve elemente u kolekciji
scala> a.forall(_ < 5)
res32: Boolean = false
jo jedna korisna metoda je find, moemo sada ukucati sledei kod:
scala> a.find(_ % 4 == 0)
res34: Option[Int] = Some(8)
evo vidimo da je to 8, vidimo da je povratna vrednost metode znaajna, jer je mogue da stvar koju mi traimo
preko metode find nije tu pa Scala je potrebno da se izbori sa tom mogunou
jo jedna interesantna metoda je partition
scala> a.partition(_ < 5)
res35: (Array[Int], Array[Int]) = (Array(1, 2, 3, 4),Array(6, 9, 5, 8))
vidimo da u ovom sluaju partition nam vraa Tuple, gde jedan deo tog para niz elemenata koji su manji od 5, a
drugi je ostatak
postoje jo neke veoma znaajne sloene funkcije, jedna od njih je reduce, koja prihvata 2 parametra:
scala> a.reduce(_+_)
res36: Int = 38
vidimo da nam rezultat vraa sumu, ali reduce je mnogo jaa od toga, jer moe da varti razliite operacije
pored ve navedenih min i max mogu da imaju parametre, npr. ukoliko imamo niz stringova, moda elimo da
naemo najkrai
scala> val niz1 = Array("this", "is", "a", "test", "and", "we", "are", "late")
niz1: Array[String] = Array(this, is, a, test, and, we, are, late)
scala> niz1.minBy(_.length)
res37: String = a

18. Strings as Sequences


stringovi takoe mogu da se ponaaju kao kolekcije i metode listi i nizova mogu biti pozvane nad stringovima u
Scala-i
na stringove moemo gledati kao na sekcvencu karaktera
npr. sada emo nad stringom pozvati funkciju filter i videti da li ima neto to je manje od slova l
15
scala> "This is a test".filter(_ < 'l')
res46: String = Thi i a e
primetite da je veliko T manje od l, znak space je manji od l, to je zato to kada poredite karaktere zapravo
poredite gde se oni nalaze u enkodiranoj sekvenci, a za veinu dananjih raunara je to ASCII ili UNICODE
moete saznati UNICODE ili ASCII vrednost karaktera
scala> 'T'.toInt
res47: Int = 84
takoe primetiete da su vrednosti veih slova manje od vrednosti manjih slova
scala> 't'.toInt
res48: Int = 116
takoe moemo izvui samoglasnike iz stringa
scala> "This is a test".filter(c => "aeiou".contains(c))
res49: String = iiae
metoda split je korisna zato to string razbija u niz string-ova, na osnovu prosleenog parametra koji je regularni
izraz
scala> "This is a test".split(" ")
res50: Array[String] = Array(This, is, a, test)

19. Lists, Recursion, and Patterns


immutable liste veoma dobro rade sa rekurzijom
napravimo sada funkciju koja prihvata vrednost sa tastature i od toga pravi listu

o def buildList(): List[String] =


o {
o val input = readLine()
o if(input == "quit")
o Nil
o else
o input :: buildList()
o }
pravimo metodu buildList koja vraa listu String-ova kao parametar
unutar f-je prihvatamo unos korisnika sa tastature
ukoliko korisnik otkuca quit, staemo sa unosom
u tom sluaju emo vratiti praznu (eng. empty) listu Nil
ukoliko ulaz nije quit, tada emo nadovezati taj input i ponovo pozvati metodu
unutar main metode, ubaciemo sledei kod:
o val lst = buildList()
o println(lst)

u ovom kodu pozivamo metodu buildList() i nakon toga tampamo na ekran unesenu list
kada pokrenemo ovo, dobijemo sledee:
o this
o is
o a
o test
o quit
List(this, is, a, test)
vidimo da se ova funkcija izvrava rekurzivno, tako to se element dodaje na poetak liste i ta funkcija ponovo
poziva, vidimo da koristimo operator cons :: (to cons onto) konstrukcija objekta koji sadri 2 vrednosti ili 2
pokazivaa na vrednosti generalniji izraz if funkcionalnog programiranja
https://en.wikipedia.org/wiki/Cons
dakle ovo je bio primer kako moemo da iskoristimo rekurziju i cons da sastavimo listu
sada emo napisati metodu koja nadovezuje stringove i zove se concatStrings, koja prihvata kao parametar listu
stringova i vraa nam jedan string
16
ukoliko je lista string-ova prazna tada funkcija e vratiti prazan string
u suprotnom emo vratiti prvi element, preko head, i funkciju concatStrings koja je pozvana na ostatku
elemenata, koji dobijamo pozivanjem tail

o def concatStrings(words: List[String]) : String =


o {
o if (words.isEmpty) ""
o else words.head + concatStrings(words.tail)
o }

sada emo u main metodi malo promeniti poziv


o val lst = buildList()
o println(concatStrings(lst))

kada pokrenemo ovaj kod dobijamo ispis na terminal-u:


o This
o is
o a
o test
o quit
Thisisatest
ovo je veoma efikasno kada radimo sa List-ama, a postoji alternativni nain kada radimo sa paternima
liste i nizovi mogu da budu koriene u pattern-ima
npr.
val Array(a, b, c) = "one two three".split(" ")
ova linija koda e uzeti niz stringova one two three podelie ih preko space-a
dakle, dobiemo niz sa 3 elementa i ove vrednosti e skladititi u promenljive a, b i c
u sluaju da ovaj string nije imao 3 elementa sa 2 space-a, ovaj kod bi pukao i to bi bio problem
sada emo napisati drugu verziju funkcije concatStrings, i nazvaemo je concatStringsPat i u njoj emo koristiti
match naredbu, a umesto if i else naredbe unutar tela ove funkcije, staviemo case
jedan case je Nil
drugi case se moe izraziti kao patern koji ukljuuje cons i to emo napisati h cons t, h za head i t za tail

o def concatStringsPat(words: List[String]) : String = words match


o {
o case Nil => ""
o case h :: t => h + concatStringsPat(t)
o }

20. Option
option je tip koji postoji u Scala
spominjali smo ga kod Find metode nad kolekcijama, jer Find metoda vraa Option
vratiemo se sada u REPL mod
definisaeno niz a
o scala> val a = Array(3, 9, 6, 1, 7, 4, 8, 2)
o a: Array[Int] = Array(3, 9, 6, 1, 7, 4, 8, 2)
ukoliko pokuamo da pronaemo prvi element koji je manji od 3
o scala> a.find(_ < 3)
o res0: Option[Int] = Some(1)
vidimo da nam je f-ja vratila Some(1)
ukoliko pokuamo da pronaemo neto vee od 10
o scala> a.find(_ > 10)
o res1: Option[Int] = None
vidimo da nam f-ja vraa None

17
ta mi moemo da uradimo sa ovim Option tipom ? Razlog zato on postoji, sigurno jeste u tome da find moe i
da ne pronae neto.
generalno pravilo u Scala-i je ukoliko kod moe da ima ili nema vrednost, odgovarajui nain da se rukuje sa tim
jeste da se koristi Option
ta moete da radite sa Option ?
ispostavlja se da postoji metoda koja omoguava da dobijete vrednost iz option-a
ali ne bi ste trebali samo da pozovetu tu metodu
da bi smo demonstrirali moemo da pozovemo metodu get nad res0
o scala> res0.get
o res2: Int = 1
razlog zato ne bi ste trebali da upotrebljavata ovu metodu, jeste ukoliko je pozovete nad None dobiete greku
o scala> res1.get
o java.util.NoSuchElementException: None.get
o at scala.None$.get(Option.scala:347)
o at scala.None$.get(Option.scala:345)
o ... 32 elided
dakle, ne elimo da regularno pozovemo metodu get
kako moemo da utvrdimo koja je vrednost tipa Option i da u sluaju je None odgovarajue postupimo ?
jedan od naina jeste upotrebom paterna
o scala> res0 match {
o | case Some(i) => println(s"Found $i")
o | case None => println("Nothing found")
o |}
Found 1

drugi nain za reavanje ovog problema ukljuuje upotrebu getOrElse


ovo je veoma dobro ukoliko postoji default-na vrednost
scala> res0.getOrElse(0)
res6: Int = 1

scala> res1.getOrElse(0)
res7: Int = 0

vidimo da iako je rezultat None, getOrElse moe sa tim da izae na kraj


Option esto je u upotrebi sa funkciom map, jer e mapiranje Some vrednosti vratiti neto, dok None e uvek biti
None

21. Text Files


tekstualni fajlovi nam najee omoguavaju da proitamo vee skupove podataka (eng. dataset)
za potrebe ovog poglavlja kreiraemo tekstualni fajl matrix.txt, koji u sebi sadri 4 X 3 matricu od 12 brojeva
rad sa fajlovima se nalazi u paketu io, koji smo ranije koristili
import scala.io.Source
sada u promenljivu source uitajmo fajl preko metode Source objekta fromFile
val source = Source.fromFile("matrix.txt")
Source vraa neto kao kolekcija to se zove iterator
osnovne metode nad interatorom su next i hasNext
takoe iterator ima dostupne metode map i filter, koje kada rade vraaju novi itertor
kada se pozove metoda fromFile, dobije se BufferedSource
dakle, source je iterator karaktera
ako ja pozovem metodu next nad ovim, vidimo da ona vraa karakter char
prilikom rada umesto da imam karakter po karakter, mnogo ee elim da imam cele linije
val lines = source.getLines()
i ova metoda getLines, vraa iterator String-ova

18
orginalni Source je bio iterator karaktera, vraao je jedan karakter u trenutku, pozivom lines imamo iterator string-
ova, koji nam vee cele linije
sada ukoliko pozovemo funkciju map, ona e biti sprovedena nad celom linijom, a to je upravo ono to elimo i da
uradimo
matrix emo izgraditi tako to emo uzeti lines i mapirati na individualne brojeve, a to emo uraditi preko f-je split
val matrix = lines.map(line => line.split(" "))
tako da nam je promenljiva matrix sada niz string-ova
sada ukoliko ne elim taj niz stringova, to mogu da dodatno mapiram u double
i u sluaju da ne elim iterator, to mogu da konvertujem u niz
val matrix = lines.map(line => line.split(" ").map(_.toDouble)).toArray
nakon to smo ovo konvertovali u niz, cela stvar je sada uitana u memoriju
i sada je jo potrebno da zatvorimo fajl
source.close()
ukoliko sada elim da sumu redova matrice odtampam u fajl mogu da iskoritim klasu PrintWriter iz Java-e, poto
Scala nema svoj PrintWriter
dodajmo paket koji to omoguava
import java.io.PrintWriter
i dodajmo sada novi objekat klase PrintWriter u kodu
val pw = new PrintWriter("rowSums.txt")
poto sam na ovaj nain otvorio fajl, potrebno je na kraju da ga zatvorim
pw.close()
sada izmeu otvaranja i zatvaranja novog fajla je potrebno da napiem kod koji pravi te sume

val source = Source.fromFile("matrix.txt")


val lines = source.getLines()
val matrix = lines.map(line => line.split(" ").map(_.toDouble)).toArray
source.close()

val pw = new PrintWriter("rowSums.txt")


matrix.foreach { row => pw.println(row.sum) }
pw.close()

vidimo sada da smo kreirali novi fajl rowSums.txt, u kome se nalaze sumirani redovi

22. Named and Default Arguments


nekada metode mogu da imaju vie parametara
dobar primer moe da bude srednja ocena studenta
o def grade(quizzes:List[Int], assignments:List[Int], tests:List[Int]) : Double =
o {
o ???
o }
izazov sada kod ove metode jeste kada je pozovemo u main-u
grade(List(45, 98), List(87, 69), List(83))
moda e se desiti da zaboravimo koji argument se odnosi na ta
Scala podrava mogunost da imate imenovane (eng. named) parametre
grade(assignments = List(45, 98), tests = List(87, 69), quizzes = List(83))
postoji mogunot kombinovanja imenovanih i neimenovanih
takoe upotreba imenovanih paramtara se esto koristi uz default-ne parametre
pretpostavimo sada da metoda grade ima trei parametar, listu testova po default-u postavljenu na Nil
def grade(quizzes:List[Int], assignments:List[Int], tests:List[Int] = Nil) : Double =
{
???
}

19
sada f-ju moemo pozvati
grade(assignments = List(45, 98), quizzes = List(83))

23. Currying and Pass-by-Name


sada elim da napiem metodu koja sabira 2 broja i vraa Int, uobiajeni nain bi bio sledei:
def add(x: Int, y: Int): Int = x + y
dakle, imamo jednu listu parametara koja prihvata 2 parametra
ako elim da sada ovo uinim curried, napisau ovu funkciju na sledei nain:
def add(x: Int)(y: Int): Int = x + y
ideja ovde jeste da samo moemo da pozovemo add i prosledimo jedan parametar, a ono nam vra funkciju koja
eka drugi parametar
ukoliko sada u main-u napiemo
val plus3 = add(3)
kompajler e prijaviti greku, jer morate eksplicitno da kaete kompajleru da ste namerno izostavili drugi
argument, tako da je potrebno da sve ovo dodate donju crtu, i time oznaavate kompajleru da ovde postoji
dodatni argument, koji jo nije obezbeen
val plus3 = add(3)_
sada vidite da je plus3 funkcija koja mapira Int u Int
sada emo proslediti taj drugi argument
val eight = plus3(5)
currying je sposobnost da se prosleuje jedan argument u trenutku
upotrebom currying type inference je inteligentniji ako imate argumente odvojene

napravimo sada metodu koja se zove threeTuple, kao ulazni parametar prihvata Double, a vraa tuple od 3
Double-a
o def threeTuple(a: Double): (Double, Double, Double) =
o {

o }

unutar te metode emo samo vratiti tuple koji se sastoji iz 3 vrednosti a

kod sada izgleda


o def threeTuple(a: Double): (Double, Double, Double) =
o {
o
o }

ukoliko sada u main-u pozovem threeTuple i prosledim 5, jasno je da u dobiti tuple od 3 broja 5
threeTuple(5)
postavlja se pitanje, ta e se desiti ukoliko prosledim neto to tipino ima razliite vrednosti, npr. math.random
threeTuple(math.random)
random je f-ja koji svaki put kada se pozove vraa novi proizvoljni (eng. random) broj
normalno prosleivanje je putem vrednosti i putem reference
ukoliko sada pozovemo metodu da odtampa, odatmpae se jedna vrednost vie puta
println(threeTuple(math.random))
(0.22396667422679561,0.22396667422679561,0.22396667422679561)
sada emo umesto obinog prosleivanja parametra tipa Double, proslediti funkciju
o def threeTuple(a:() => Double): (Double, Double, Double) =
o {
o
o }
dakle ova funkcija sada ne prihvata nikakve parametre a vraa Double
sada moramo da drugaije pozovemo ovu funkciju
20
o println(threeTuple(() => math.random))
takoe emo promeniti telo metode threeTuple
o def threeTuple(a:() => Double): (Double, Double, Double) =
o {
o (a(), a(), a())
o }
sada je jasno da 3 puta pozivamo ovu funkciju i zato emo dobiti 3 proizvoljna broja
(0.8738273751769043,0.8674258803780766,0.3015206381608083)
Scala ima u sebi funkcionalnost pass-by-name koja uproava pokazani metod rada
u metodi threeTuple emo iskoristiti prosleivanje po imenu, tako da imamo f-ju
o def threeTuple(a: => Double): (Double, Double, Double) =
o {
o (a, a, a)
o }
koju pozivamo na sledei nain:
println(threeTuple(math.random))
kada se pokrene dobijamo rezultat 3 proizvoljna broja u tuple-u

21

You might also like