Professional Documents
Culture Documents
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
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)
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
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
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()
}
}
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)
scala> res1(2)
res3: Char = y
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)
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> res0.toList
10
res12: List[Int] = List(9, 4, 99, 2, 5)
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)
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))
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
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
scala> res1.getOrElse(0)
res7: Int = 0
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
vidimo sada da smo kreirali novi fajl rowSums.txt, u kome se nalaze sumirani redovi
19
sada f-ju moemo pozvati
grade(assignments = List(45, 98), quizzes = List(83))
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 }
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