×
{{errorMessage}}
Faggruppe for Scala & JVM
Et moderne, statisk typet, objekt-funksjonelt programmeringsspråk på JVM-en
Basically, it’s the future
// En ikke endrbar verdi, tenk final i Java
val fødselsnummer = "02017912345"
// En endrbar variabel
var navn: String = "Torbjørn Vatn"
// En metode med returverdi
def beregnAlder(personNummer: String): Int = {
val alder = 0// kode som beregner alder
alder
}
// En metode uten returverdi, tenk void i Java
def endreNavn(nyttNavn: String) {
navn = nyttNavn
}
// En if/else er en expression, så den returnerer en verdi
val er2StørreEnn4 = if (2 > 4) "JA" else "NEI"
// En enkel for som looper over en range fra 1 til 10
for (i <- 1 to 10) { println(i) }
// En funksjon fra to Ints til Boolean lagres i en verdi
val erStørreEnn = (x: Int, y: Int) => x > y
// Funksjonen kalles med to argumenter
if (erStørreEnn(2,4)) "JA" else "NEI"
Objektorientert programmering
class Person
val p = new Person
class Person(val name: String, var age: Int)
val p = new Person("Bob", 25)
p.name // Bob
p.age = 26
class Person(age: Int) {
val category = if (age < 35) "young" else "old"
def sayHi = "Hi, I’m " + category
}
new Person(30).sayHi //Hi, I’m young
class Date(val time: Long) {
def this(date: Date) = this(date.time)
}
object Logger {
def log(msg: String) = println(msg)
}
Logger.log("It’s all good!")
class Person(val name: String, val age: Int)
//I samme fil
object Person {
def apply(name: String, age: Int) = new Person(name, age)
}
val p = Person("Frode", 33)
trait Animal {
def greet = "I’m an animal"
}
class Dog extends Animal
class Fox extends Animal
trait Animal {
def say: String
def greet = "I’m an animal that says " + say
}
class Dog extends Animal {
def say = "woof"
}
class Fox extends Animal {
def say = ???
}
trait Animal {
def say: String
}
trait Fourlegged
trait Furry
class Dog extends Animal with Fourlegged with Furry {
def say = "woof"
}
scala> 4 :: List(1, 2, 3) // Prepend, O(1)
res0: List[Int] = List(4, 1, 2, 3)
scala> List(1, 2, 3) ::: List(4) // Append, O(n), foretrekk prepend
res1: List[Int] = List(1, 2, 3, 4)
scala> val numbers = List(1,2,3)
numbers: List[Int] = List(1, 2, 3)
scala> numbers.map((x: Int) => x + 1)
res0: List[Int] = List(2, 3, 4)
scala> val myList = List(1, 2, 3, 4, 5, 6)
myList: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> myList.filter((x: Int) => x > 3)
res0: List[Int] = List(4, 5, 6)
//Adder et element til begynnelsen av listen
def ::(x: A): List[A]
//Adder en liste til begynnelsen av listen
def :::(prefix: List[A]): List[A]
//Velger det første elementet i listen
def head: A
//Velger de resterende (foruten første) elementene i listen
def tail: A
//Velger de første n elementene i en liste
def take(n: Int): List[A]
//Velger de siste n elementene i en liste
def takeRight(n: Int): List[A]
//Velger alle elementer bortsett fra de første n elementene i en liste
def drop(n: Int): List[A]
//Lager en liste av par ut fra to lister
def zip[B](that: GenIterable[B]): List[(A, B)]
En avansert versjon av switch
i Java
def toYesOrNo(choice: Int) = choice match {
case 1 => "yes"
case 0 => "no"
case _ => "error"
}
scala> toYesOrNo(1)
res0: String = yes
scala> toYesOrNo(10)
res1: String = error
def f(x: Any) = x match {
case i:Int => "integer: " + i
case _:Double => "a double"
case s:String => "I want to say " + s
}
scala> f(2.0)
res0: String = a double
def fact(n: Int) = n match {
case 0 => 1
case n => n * fact(n - 1)
}
Uten pattern matching:
def fact(n: Int) =
if (n == 0) 1
else n * fact(n - 1)
Klasser med god støtte for pattern matching
case class Person(firstName: String, lastName: String)
scala> val person = Person("Ola", "Nordmann")
person: Person = Person(Ola,Nordmann)
scala> person.firstName + " " + person.lastName
res0: String = Ola Nordmann
def finnOla(person: Person) = person match {
case Person("Ola", 32) => println("Fant Ola 32!")
case Person("Ola", alder) => println("Fant en annen Ola som er " + alder)
case Person(navn, _) if navn.startsWith("O") => println("Fant en med navn på O")
case Person(navn, alder) => println("Fant: " + navn + ", " + alder)
}
def checkIfFirstPersonIsOla(persons: List[Person]) =
persons match {
case List(Person("Ola", _), _*) => true
case _ => false
}
scala> val persons = List(Person("Ola", "test"),
| Person("test", "test"))
persons: List[Person] = List(Person(Ola,test), Person(test,test))
scala> checkIfFirstPersonIsOla(persons)
res0: Boolean = true
_*
betyr villlkårlig mange følgende elementer
Faggruppe for Scala & JVM
//immutable value, type inferred
val name = "Frode"
//immutable value with type
val name2: String = "Frode"
//method
def sayHiTo(name: String) = s"Hi $name"
//method with explicit return type
def add(a: Int, b:Int): Int = a + b
//result of last expression is returned
val date = {
println("getting the date")
new Date()
}
//if is an expression
def checkLength(str: String) = if (str.length < 50) "ok" else "too long"
//try catch is an expression
val head = try {
Source.fromFile("app.log").getLines().take(10)
} catch {
case _: IOException => List()
}
//function value
val add = (a: Int, b: Int) => a + b
//convert method to function
val replaceAll = "Frode".replaceAll _
replaceAll("e", "3")
//res0: String = Frod3
//functions as arguments
def combine(a: Int, b: Int, func: (Int, Int) => Int) = func(a, b)
combine(2, 3, _ * _)
//res1: Int = 6
class Person(val name: String, val age: Int) {
override def toString = name + " " + age
}
//object with apply factory method
object Person {
def apply(name: String, age: Int) = new Person(name, age)
}
Person("Frode", 33)
//res2: Person = Frode 33
trait Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf(value: String) extends Tree
Node(Leaf("left"), Leaf("right")) match {
case Node(_, Leaf(value)) => "right tree was leaf with value " + value
case Node(_, right) => "right was " + right
}
//res3: String = right tree was leaf with value right
Som i Java, men med [T] i stedet for <T>
//value of generic type List with type argument String
val names: List[String] = List("Arild", "Sjur", "Frode")
//generic method with one type parameter
def lastElement[A](list: List[A]) = list.last
//generic mapping function with two type parameters
def map[A, B](value: A)(func: A => B): B = func(value)
map("Frode".toList)(lastElement)
//res4: Char = e
... men mye mer avansert!
$ cd scalakurs/oppgaver/del-2
$ ./sbt
[info] Loading project definition from /Users/frode/dev/scalaogjvm/scalakurs/oppgaver/del-2/project
[info] Set current project to scalakurs-ntnu-del2 (in build file:/Users/frode/dev/scalaogjvm/scalakurs/oppgaver/del-2/)
>
> ~test
> <enter>
> clean
> compile
> run
> eclipse
> gen-idea
Deretter kan du velge File -> Open -> scalakurs/oppgaver/del-2
def even(start: Int, end: Int) =
for (i <- start until end if i % 2 == 0) yield i
scala> even(0, 20)
res0: Vector[Int] = Vector(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)
scala> for( x <- (1 to 2 ); y <- (1 to 3) ) yield (x,y)
res0: Vector[(Int, Int)] = Vector((1,1), (1,2), (1,3), (2,1), (2,2), (2,3))
def getFactors(n: Long) =
for (x <- ( 1 to n ); if n % x == 0) yield x
scala> getFactors(20)
res0: Vector[Int] = Vector(1, 2, 4, 5, 10, 20)
for(x <- c1; y <- c2; z <-c3) {...}
// compiles to
c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
for(x <- c1; y <- c2; z <- c3) yield {...}
// compiles to
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
for(x <- c; if cond) yield {...}
// compiles to (in Scala 2.8+)
c.withFilter(x => cond).map(x => {...})
Option[A]
Some[A] None
val something: Option[String] = Some("A string")
val nothing: Option[String] = None
something.isEmpty
//res4: Boolean = false
nothing.isEmpty
//res5: Boolean = true
something.getOrElse("")
//res6: String = A string
nothing.getOrElse("")
//res7: String = ""
«Null References: The Billion Dollar Mistake»
Sir Tony Hoare
val name: String = request.getParameter("name")
val upperCaseName = if (name != null) {
val trimmed = name.trim
if (!trimmed.isEmpty) {
trimmed.toUpperCase
} else {
null
}
} else {
null
}
val name: Option[String] = request.getParameter("name")
val upprCaseName = name map (_.trim) filter (!_.isEmpty) map (_.toUpperCase)
val myOptional: Option[String] = Some("Hello")
myOptional.foreach(println)
// Hello
myOptional.exists(_.startsWith("H"))
//res0: Boolean = true
myOptional.map(_.toLowerCase)
//res2: Option[String] = Some(hello)
myOptional.flatMap(s => Some(s + " Frode"))
//res3: Option[String] = Some(Hello Frode)
myOptional.getOrElse("!!")
//res4: String = Hello
val optionalPerson: Option[Person] = Some(Person("Frode"))
optionalPerson match {
case Some(Person("Frode")) => println("Fant Frode")
case Some(_) => println("Fant noen andre")
case None => println("Ikke en person")
}
val firstName: Option[String] = Some("Arild")
val lastName: Option[String] = Some("Nilsen")
val fullName = for {
first <- firstName
last <- lastName
} yield first + " " last
Try[A]
Succes[A] Failure[A]
case class Kunde(alder: Int)
class Sigaretter
case class ForUngException(melding: String) extends Exception(melding)
def kjøpSigg(kunde: Kunde): Sigaretter =
if (kunde.alder < 18)
throw ForUngException(s"Kunden må være over 18, men er ${kunde.alder}")
else new Sigaretter
val ungKunde = Kunde(15)
val melding = try {
val røyken = kjøpSigg(ungKunde)
s"Her har du $røyken din!"
} catch {
case ForUngException(mld) => mld
}
println(melding)
case class Kunde(alder: Int)
class Sigaretter
case class ForUngException(melding: String) extends Exception(melding)
def kjøpSigg(kunde: Kunde): Sigaretter =
if (kunde.alder < 18)
throw ForUngException(s"Kunden må være over 18, men er ${kunde.alder}")
else new Sigaretter
val ungKunde = Kunde(15)
val melding = Try(kjøpSigg(ungKunde)) match {
case Success(røyken) => s"Her har du $røyken din!"
case Failure(e) => e.getMessage
}
println(melding)
case class Kunde(alder: Int)
trait Produkt
class Sigaretter extends Produkt
class Tyggis extends Produkt
case class ForUngException(melding: String) extends Exception(melding)
def kjøpSigg(kunde: Kunde): Try[Produkt] =
if (kunde.alder < 18)
Failure(ForUngException(s"Kunden må være over 18, men er ${kunde.alder}"))
else
Success(new Sigaretter)
val ungKunde = Kunde(15)
val produkt = kjøpSigg(ungKunde) recover {
case fue: ForUngException => new Tyggis
}
println(s"Hurra jeg fikk kjøpt ${produkt.get}")
val keyValues = for {
keys <- Try(Source.fromFile("keys.txt").getLines())
values <- Try(Source.fromFile("values.txt").getLines())
} yield keys zip values toMap
val result: Map[String, String] = keyValues.getOrElse(Map())
getOrElse
map / flatMap
filter / foreach
for comprehensions
pattern matching
A Future is a read-handle to a single value (read-many) that may be available within a specific time-frame
A Promise is a write-handle to a single value (write-once) that should be made available within a specific time-frame
println("Test print before future")
val s = "hello"
val f = future {
Thread.sleep(10)
s + " future!"
}
println("Test print after future")
// Completely asynchronous
f.onSuccess { case s => println(s) }
// Blocks until the future is ready
Await.ready(f, Duration.Inf)
Test print before future
Test print after future
hello future!
//Asynchronously processes the value in
//the future once the value becomes available.
def foreach[U](f: T => U): Unit
//Creates a new future by applying a function to the successful
//result of this future.
def map[S](f: T => S): Future[S]
//Creates a new future by applying a function to the successful
//result of this future, and returns the result of the function
//as the new future.
def flatMap[S](f: T => Future[S]): Future[S]
//Creates a new future by filtering the value of the current future
//with a predicate.
def filter(p: T => Boolean): Future[T]
val riskyRes = future { riskyWork() }
val safeRes = future { safeWork() }
val finalRes = riskyRes recoverWith {
case e: IllegalArgumentException => safeRes
}
val keys = future { readFile("keys.txt") }
val values = future { readFile("values.txt") }
val data = keys.zip(values)
val hashMap = data.map((ls: (List[String], List[String])) => {
ls._1.zip(ls._2).toMap
})
hashMap.recover {
case e: FileNotFoundException => {
Map[String, String]()
}
}.onSuccess {
case map => {
println(map)
}
}
Await.result(hashMap, Duration.Inf)
val p = promise[T]
val f = p.future
val producer = future {
val result = produceSomething()
p success result
continueDoingSomethingUnrelated()
}
val consumer = future {
startDoingSomething()
f onSuccess {
case res => doSomething(res)
}
}
class Articles extends ScalatraServlet {
get("/articles/:id") { // <= dette er en route-matcher
// dette er en action
// som henter en artikkel med den spesifiserte :id
}
post("/articles") {
// submit/lage en artikkel
}
put("/articles/:id") {
// oppdatere en artikkel med en spesifikk :id
}
delete("/articles/:id") {
// slette en artikkel med en spesifikk :id
}
}
class Articles extends ScalatraServlet {
get("/articles/:id") {
<html>
<body>
<p>Ah, article with id {params("id")} is a classic!</p>
</body>
</html>
}
}
{
name: "sue",
age: 26,
status: "A",
groups: [ "news", "sports"]
}
tar zxvf mongodb-linux-x86_64-2.4.8.tgz
mkdir -p /home/sjur/mongodbdata
mongodb --dbpath /home/sjur/mongodbdata
mongo
help
db.x.insert({_id: 10, type: "misc", item: "card", qty: 15})
db.x.update({type:"book", item:"journal"},{$set:{qty:9}}, {upsert:true})
db.x.save({type: "book", item: "notebook", qty: 40})
db.inventory.find({})
db.x.find({type: "snacks"})
db.x.find({type: {$in: ['food', 'snacks']}})
db.x.find({type: 'food', price: {$lt: 9.95}})
db.x.find({$or: [{ qty: {$gt: 100}}, {price: {$lt: 9.95}}]})
JavaScript rammeverk for utvikling
av single-page applikasjoner
×
{{errorMessage}}
-
{{article.title}}
av
{{article.author}}
function MainController($scope, dataService) {
$scope.showError = false;
dataService.getAllArticles().then(
function(articles) { $scope.articles = articles; },
function() { showError('feil ved henting av artikler'); }
);
function showError(message) {
$scope.showError = true;
$scope.errorMessage = message;
}
$scope.submitArticle = function(article) {
dataService.addArticle(article).then(
function() { $scope.articles.push(article); },
function() { showError('feil ved lagring av artikkel'); }
);
}
};
app.factory('dataService', function($http) {
return {
getAllArticles: function() {
return $http.get('/articles').then(function(resp) {
return resp.data;
});
},
addArticle: function(article) {
return $http.post('/articles', article).then(function(resp) {
return resp.data;
});
}
}
});
#ArticlesController
GET /articles #get all articles
POST /articles #create new article
GET /articles/:id #get single article
PUT /articles/:id #update existing article
DELETE /articles/:id #remoeve article
POST /articles/:id/comments #create new comment on article
DELETE /articles/:id/comments #delete all comments from article
#article with comments
{
"_id": "1234zxcvdas",
"author": "Frode",
"title": "A blogpost",
"content": "Loong and informative post"
"comments": [
{
"author": "Sjur",
"content": "Nice post!",
},
{
"author": "Arild",
"content": "Could be shorter."
}
]
}