scala - java · scala> class class a { def size = 4 } defined class a scala> class b extends...
TRANSCRIPT
ScalaNejslavnější operní dům Itálie
předminulého století....
Jiří 'Jira' Marešvíc než 10 let s JavouGREEN Center -> BOSCH -> ČSAD SVT Prahazaměřuji se na proces vývoje a na kvalitu kódu
jirablog.blogspot.com twitter.com/jiramares
Ondra 'Satai' Nekolasedm let s Javou (v dobrém i zlém)Globe Internet -> Active 24 -> Wirenode -> Sun Microsystems (WTK team)twitter.com/sataisatai.posterous.comwww.nekola.czstarosta v Lokále
SCALAPrvní kroky
ScaLaScalable Language
Scala v hyperkostcejazyk pro JVM (a .NET)objektový jazykfunkcionální jazykakademický projektprakticky použitelný jazyksnadná spolupráce s Javou (a dalšími JVM jazyky)silný typový systém...a není potřeba být moc ukecanýsíla v knihovnách spíše než v jazycevysoký výkon
Objektový jazyk(skoro) vše je objektoperace s čísly a booleany většinou kompilované jako instrukce nad primitivnímy typyneexistují statické metody a datajednoduchá dědičnost + traity
Tři módyinteraktivní mód
REPL (Read-Eval-Preview Loop)
DEMO
Tři módyinteraktivní mód
REPL (Read-Eval-Preview Loop)script
parametry v poli args (Array[String])
třídy v souborechi více public tříd v jednom souborudobře škáluje a spolupracuje s antem, mavenem, IDEs...
Funkcionální jazykfunkce je objekt (first class value)
můžeme předávat a ukládat do proměnné funkci mohu definovat uvnitř jiné funkcemohu pro definici použít funkční literál (funkce beze jména, λ)
funkce je zobrazení (žádné sideefecty)ruku v ruce jdou immutable typylepší škálovatelnost, protože nemusím synchronizovatcachování výpočetně náročných volání
A jdeme na to......ale raději pomalu
Val
scala> val x : Int = 1x: Int = 1
scala> val y = 2y: Int = 2
scala> val z = x + yz: Int = 3
scala> z = 3<console>:7: error: reassignment to val z = 3 ^
Var
scala> val x1 : Int = 1x1: Int = 1
scala> val y1 = 2y1: Int = 2
scala> var z1 = x1 + y1z1: Int = 3
scala> z1 = 4z1: Int = 4
scala> z1res0: Int = 4
A nejlínější konstanta na světě
scala> var x2 : Int = 1x2: Int = 1
scala> val y2 = 2y2: Int = 2
scala> lazy val z2 = x2 + y2z2: Int = <lazy>
scala> x2 = 3x2: Int = 3
scala> z2res1: Int = 5
Funkce (živočicháře)
scala> def sum(a:Int, b:Int) : Int = a + bsum: (a: Int,b: Int)Int
scala> def multi(a:Int, b:Int) = a * bmulti: (a: Int,b: Int)Int
scala> def succ(a: Int) : Int = { | return sum(a, 1) | } succ: (a: Int)Int
scala> sum(1, 2)res4: Int = 3
if/else je výraz
def plural(noun: String) = if ("man" == noun) "men" else noun + "s"
if není tak úplně výraz (vlastně vůbec ne)
scala> val a = 4a: Int = 4 scala> if (4 == a) println("Je to ctyri")Je to ctyri
scala> if (5 == a) println("Je to pet") <<tady nic neni>>
Faktoriál - povinná složka každé učebnice
scala> def factorial(n : Int): Int = | if (0 == n) 1 else n * factorial(n-1)factorial: (n: Int)Int
scala> factorial(6) res12: Int = 720
case class
scala> case class Pivo(jmeno : String, plnotucne : Boolean)defined class Pivo
scala> val bernard = Pivo("Bernard", true) bernard: Pivo = Pivo(Bernard,true)
scala> bernard.jmeno res1: String = Bernard
scala> bernard.toStringres2: String = Pivo(Bernard,true)
case class
case class Pivo(jmeno : String, plnotucne : Boolean){ def vypijS(kolega : String) = println("Gloglo " + jmeno + " s " + kolega)} scala> val bernard = Pivo("Bernard", true) bernard: Pivo = Pivo(Bernard,true)
scala> bernard.vypijS("Petr") Gloglo Bernard s Petr
scala> bernard vypijS "Pavel" Gloglo Bernard s Pavel
I operátor je jen metoda
scala> val i = 1i: Int = 1
scala> i + 1 res15: Int = 2
scala> i.+(1)res14: Int = 2
Typová inference - kam orli nelétají
scala> def factorial(n : Int) = | if (0 == n) 1 else factorial(n-1)<console>:5: error: recursive method factorial needs result type if (0 == n) 1 else factorial(n-1) ^
Funkce je taky... objekt
scala> (x: Int, y: Int) => x + y res14: (Int, Int) => Int = <function2>
scala> val mojeFunkce = (x: Int, y: Int) => x + ymojeFunkce: (Int, Int) => Int = <function2>
scala> mojeFunkce(1,2)res15: Int = 3
scala> val taSamaFunkce = mojeFunkcetaSamaFunkce: (Int, Int) => Int = <function2>
Seznam: najdu tam, co...
scala> val inty = 1 :: 2 :: 3 :: 4 :: Nilinty: List[Int] = List(1, 2, 3, 4)
scala> inty == List(1, 2, 3, 4)res17: Boolean = true
scala> 1 :: 2 :: List(3, 4) res18: List[Int] = List(1, 2, 3, 4)
scala> List(1, 2) ::: List(3, 4) res19: List[Int] = List(1, 2, 3, 4)
A znáte ten scalovej fór?
scala> val inty = 1 :: 2 :: 3 :: 4 :: Nilinty: List[Int] = List(1, 2, 3, 4)scala> for (i <- inty) | println(i) 1234
scala> for (i <- inty if i > 2) println (i)34
A znáte ten scalovej fór?
val inty = 1 to 10 inty: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
for (i <- inty) yield i res0: RandomAccessSeq.Projection[Int] = RangeM(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val oddies = for (i <- inty if (i % 2 == 1 )) yield ioddies: Seq.Projection[Int] = RangeFM(1, 3, 5, 7, 9)
Jde to i knihovnami...
scala> val inty = 1 to 10 inty: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> inty.filter( (x : Int) => x > 6)res2: Seq.Projection[Int] = RangeF(7, 8, 9, 10)
scala> inty.filter( _ > 6) res5: Seq.Projection[Int] = RangeF(7, 8, 9, 10)
Jde to i knihovnami...
scala> val inty = 1 to 10 inty: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> def isOdd(n : Int) = 1 == (n % 2)isOdd: (Int)Boolean
scala> inty.filter( x => isOdd(x) )res7: Seq.Projection[Int] = RangeF(1, 3, 5, 7, 9)
scala> inty.filter( isOdd(_) )res6: Seq.Projection[Int] = RangeF(1, 3, 5, 7, 9)
scala> inty.filter( isOdd ) res3: Seq.Projection[Int] = RangeF(1, 3, 5, 7, 9)
scala> inty filter isOddres3: Seq.Projection[Int] = RangeF(1, 3, 5, 7, 9)
Nejen filtr...
scala> val inty = 1 to 10 inty: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> inty.map( _ * 10)res8: RandomAccessSeq.Projection[Int] = RangeM(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
scala> inty.reduceLeft( _ + _)res9: Int = 55
scala> inty.foldLeft(100)(_ + _)res11: Int = 155
Ekvivalenty k primitivním typům
předek všech je AnyVal(obvykle) se generuje slušný bytecodeByte, Short, Int, Long, Char, String, Float, Double, Booleanliterály jsou stejné jako v JavěUnit místo void
Multiline String
val s = """Dei Kobol una apita uthoukaranaUkthea mavatha gaman kerimutaObe satharane mua osavathamanabantaApi obata yagnya karama"""
s: java.lang.String = Dei Kobol una apita uthoukaranaUkthea mavatha gaman kerimutaObe satharane mua osavathamanabantaApi obata yagnya karama
všimněte si - java.lang.String
"Operátory"
scala> val n = 42n: Int = 42
scala> n + 3res17: Int = 45
scala> n.+(3)res18: Int = 45
scala> -nres19: Int = -42
scala> n.unary_- res23: Int = -42
Rovnosti a nerovnostiscala> val x = 1 :: 2 :: 3 :: Nilx: List[Int] = List(1, 2, 3)
scala> val y = 1 :: 2 :: 3 :: Nily: List[Int] = List(1, 2, 3)
scala> x == yres24: Boolean = true
scala> x eq yres25: Boolean = false
scala> x != yres26: Boolean = false
scala> x ne yres27: Boolean = true
Acociativita a priorita
operátory končící dvojtečkou jsou asociativní zprava, jinak zleva
scala> 1 :: 2 :: Nilres0: List[Int] = List(1, 2)
scala> Nil.::(2).::(1)res1: List[Int] = List(1, 2)
jinak určuje první znaknfixové operátory
|, ^, &, < >, =, !, :, + -, * / %, ~prefixové operátory
+, -, !, ~
case class - opakování
case class Pivo(jmeno : String, plnotucne : Boolean) { def vypijS(kolega : String) = println("Gloglo " + jmeno + " s " + kolega)} scala> val bernard = Pivo("Bernard", true) bernard: Pivo = Pivo(Bernard,true)
scala> bernard.vypijS("Petr") Gloglo Bernard s Petr
scala> bernard vypijS "Pavel" Gloglo Bernard s Pavel
Classa běžná, commonováclass Osoba(pJmeno:String, pPrijmeni:String) { val jmeno = pJmeno val prijmeni = pPrijmeni def vypis() = println("Osoba: " + jmeno + " " + prijmeni) }
scala> val plukovnik = new Osoba("Saul", "Tight")plukovnik: Osoba = Osoba@a87cbde
scala> plukovnik.vypis() Osoba: Saul Tight
scala> plukovnik.jmenores31: String = Saul
Dědičnostclass Cylon(jmeno: String, prijmeni: String, pModel: Int) extends Osoba(jmeno, prijmeni) { val model = pModel override def vypis() = println("Cylon: " + jmeno + " " + prijmeni + " ma plan") }
scala> val sharon = new Cylon("Sharon", "Valeri", 8)sharon: Cylon = Cylon@791d5d85
scala> sharon.jmeno res32: String = Sharon
scala> sharon.vypisCylon: Sharon Valeri ma plan
Jak zbytečně nepsal kopírování položekclass Zvire(val jmeno: String, val druh: String){ def vypis() = println("zvire: " + jmeno)}
scala> val amina = new zvire("Amina", "zirafa")amina: Zvire = Zvire@42c9aff0
scala> amina.vypiszvire: Amina
scala> amina.druhres35: String = zirafa
Konstruktor
to, co je v těle třídy funguje jako konstruktorpokud chceme více přetížených konstruktorů, tak stačí definovat metodu jménem thispomocný konstruktor musí volat jako první akci this()volání konstruktoru předka
class A(f: Int, g: String) extends B(f) { }
Obzvláště dementní příklad (by OSN)
class Foo(label: String) { require(label != null) println(label); def this(label:String, i: Int) = { this(label + " " + i) }}
scala> new Foo("ahoj")ahojres36: Foo = Foo@455d54a7
scala> new Foo("ahoj", 3)ahoj 3res37: Foo = Foo@25719b33
Bude se vám hodit u zkoušky
jedno jsoumetoda bez parametru def size = 4 atribut val size = 4
atributy a metody jsou v jednom namespaceje možné metodu overridovat pomocí val
scala> classclass A { def size = 4 }defined class A
scala> class B extends A { override val size = 3 }defined class B
Singleton (Dagi promine)
object SoLonely { val stav = "Lonely"}
scala> SoLonely.stavres38: java.lang.String = Lonely
Samozřejmě není tak úplně jedináček!
Třída a její kumpánclass WorldlyGreeter(greeting: String) { def greet() = { val worldlyGreeting = WorldlyGreeter.worldify(greeting) println(worldlyGreeting) }}object WorldlyGreeter { def apply(s: String) = new WorldlyGreeter(s) def worldify(s: String) = s + ", world!"}val greeter = WorldlyGreeter("Hallo")
Řízení běhu
if/else expressionif neexpresion (Unit)while a do-while neexpressionsfor expressiontry/catch/finally expressionmatch expression - pattern matching
nejedná se o REGEXPy!neexistuje break a continue, lze je odsimulovatnejstylovějším způsobem řízení je rekurze
Funkce v Lokále
scala> def vnejsi(): Unit = { | def vnitrni() : Int = 42 | println(vnitrni()) | }vnejsi: ()Unit
scala> vnejsi()42
Funkce je taky... objekt
scala> (x: Int, y: Int) => x + y res14: (Int, Int) => Int = <function2>
scala> val mojeFunkce = (x: Int, y: Int) => x + ymojeFunkce: (Int, Int) => Int = <function2>
scala> mojeFunkce(1,2)res15: Int = 3
scala> val taSamaFunkce = mojeFunkcetaSamaFunkce: (Int, Int) => Int = <function2>
Closures = funkce s volňáskem
scala> var another = 10another: Int = 10
scala> val count = (x: Int) => x + anothercount: (Int) => Int = <function1>
scala> count(10)res0: Int = 20
scala> another = 15another: Int = 15
scala> count(10)res1: Int = 25
Částečně aplikované funkce na curry
scala> def sum(x: Int, y: Int) = x + ysum: (x: Int,y: Int)Int
scala> def succ(x : Int) = sum(x, 1) succ: (x: Int)Int
scala> succ(1)res16: Int = 2
scala> val succ2 = (x : Int) => sum(x, 1)succ2: (Int) => Int = <function>
scala> succ2(3)res16: Int = 4
Lazy parametry - podle jména
scala> def log(toLog: Boolean, msg: => String) = | if (toLog) println("log: " + msg)log: (toLog: Boolean,msg: => String)Unit
scala> def message(s1: String, s2: String) = { | println("Jsme tu :-)") | s1 + s2 |}message: (s1: String,s2: String)java.lang.String
scala> log(true, message("A", "B"))Jsme tu :-)log: AB
scala> log(false, message("A", "B"))
Trait - mocné rozhraní
trait je interface, ale může obsahovat:definici metodyatributy
trait se liší od třídynemůže mít parametry - nejde trait A(i: Int) {}super je v třídách staticky vyhodnocované v traitech dynamicky
trait se mixuje do (mix-in) třídy pomocí extendsextends nebo withpři mixování více traitů záleží na jejich pořadítraity jsou lepší než interfacy a než vícenásobná dědičnost
Trait na živo
scala> traittrait T { def t = 3 }defined trait T
scala> class Adefined class A
scala> def a = new A with Ta: A with T
scala> a.tres12: Int = 3
scala> class B extends Tdefined class B
scala> class C extends A with Tdefined class C
Pattern matching
potřebujeme case classes jde to i bez nich
case class znamá, že compilátor:vytvoří companion object s factory metodouvšechny parametry třídy dostanou prefix valnaimplementuje metody toString, equals, hashcode
Picí test
class Piti case class Nealko(nazev: String) extends Piticase class Alko(obsahAlkoholu: Int, nazev: String) extends Piti
def vypij(piti: Piti) = piti matchmatch { case Nealko(nazev) => println("Muzes kolik chces " + nazev) case Alko(procenta, nazev) => if (procenta < 10) println ("Muzes i " + nazev) else println("Nemuzes " + nazev + " protoze obsahuje " + procenta + " alkoholu")}
scala> vypij(new Nealko("Cola"))Muzes kolik chces Cola
scala> vypij(new Alko(8, "Pivo"))Muzes i Pivo
scala> vypij(new Alko(30, "Vodka"))Nemuzes Vodka protoze obsahuje 30 alkoholu
Neměnitelné listí
List - podstatné metody jsou head, tail a isEmptyisEmpty
podporuje pattern matchingscala> val List(a, b, c) = 1 :: 2 :: 3 :: Nila: Int = 1b: Int = 2c: Int = 3
přístup k prvkům pomocí kulatých závorekscala> valval l = 1 :: 2 :: 3 :: Nill: List[Int] = List(1, 2, 3)
scala> l(1)res18: Int = 2
scala> l.apply(1)res20: Int = 2
Mapy a tupláky
scala> val map = Map(1 -> "1", 2 -> "2")map: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,1), (2,2))
scala> map(1)res19: java.lang.String = 1
scala> def viceNavratovychHodnot = (1,2.0,"Pozdrav")viceNavratovychHodnot: (Int, Double, java.lang.String)
scala> valval (i, d, s) = viceNavratovychHodnoti: Int = 1d: Double = 2.0s: java.lang.String = Pozdrav
Jak udělat v kódu pořádný zmatek
scala> implicitimplicit def int2String(x: Int) = x.toStringint2String: (x: Int)java.lang.String
scala> def a(x: String) = println("Mam " + x)a: (x: String)Unit
scala> a(1)Mam 1