learnxinyminutes-docs/de-de/scala-de.html.markdown

843 lines
23 KiB
Markdown
Raw Normal View History

2015-10-16 15:13:49 +03:00
---
language: Scala
contributors:
- ["George Petrov", "http://github.com/petrovg"]
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
- ["Geoff Liu", "http://geoffliu.me"]
- ["Ha-Duong Nguyen", "http://reference-error.org"]
2015-10-28 10:18:27 +03:00
- ["Dennis Keller", "github.com/denniskeller"]
2015-10-16 15:13:49 +03:00
translators:
- ["Christian Albrecht", "https://github.com/coastalchief"]
2017-09-08 14:54:54 +03:00
- ["Jonas Grote", "https://github.com/exic"]
2015-10-17 19:33:54 +03:00
filename: learnscala-de.scala
2015-10-16 15:13:49 +03:00
lang: de-de
---
2017-09-08 13:38:30 +03:00
Scala ist eine funktionale und objektorientierte Programmiersprache
für die Java Virtual Machine (JVM), um allgemeine Programmieraufgaben
zu erledigen. Scala hat einen akademischen Hintergrund und wurde an
2015-10-16 15:13:49 +03:00
der EPFL (Lausanne / Schweiz) unter der Leitung von Martin Odersky entwickelt.
2017-09-08 13:38:30 +03:00
```scala
2015-10-28 10:18:27 +03:00
/*
2017-09-08 14:54:54 +03:00
Scala-Umgebung einrichten:
2015-10-16 15:13:49 +03:00
1. Scala binaries herunterladen- http://www.scala-lang.org/downloads
2. Unzip/untar in ein Verzeichnis
2017-09-08 14:54:54 +03:00
3. das Unterverzeichnis `bin` der `PATH`-Umgebungsvariable hinzufügen
2015-10-16 15:13:49 +03:00
4. Mit dem Kommando `scala` wird die REPL gestartet und zeigt als Prompt:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
scala>
2017-09-08 13:38:30 +03:00
Die REPL (Read-Eval-Print Loop) ist der interaktive Scala Interpreter.
Hier kann man jeden Scala Ausdruck verwenden und das Ergebnis wird direkt
ausgegeben.
2017-09-08 14:54:54 +03:00
Als nächstes beschäftigen wir uns mit ein paar Scala-Grundlagen.
2015-10-28 10:18:27 +03:00
*/
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// 1. Grundlagen
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// Einzeilige Kommentare beginnen mit zwei Slashes.
2015-10-16 15:13:49 +03:00
/*
2017-09-08 14:54:54 +03:00
Mehrzeilige Kommentare starten mit einem Slash-Stern
und enden mit einem Stern-Slash.
2015-10-16 15:13:49 +03:00
*/
2017-09-08 14:54:54 +03:00
// Einen Wert und eine zusätzliche neue Zeile ausgeben:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
println("Hello world!")
println(10)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Einen Wert ohne eine zusätzliche neue Zeile ausgeben:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
print("Hello world")
2015-10-28 10:18:27 +03:00
/*
2017-09-08 13:38:30 +03:00
Variablen werden entweder mit var oder val deklariert.
2017-09-08 14:54:54 +03:00
Deklarationen mit val sind immutable, also unveränderlich.
Deklarationen mit var sind mutable, also veränderlich.
2017-09-08 13:38:30 +03:00
Immutability ist gut.
2015-10-28 10:18:27 +03:00
*/
2015-10-16 15:13:49 +03:00
val x = 10 // x ist 10
2017-09-08 14:54:54 +03:00
x = 20 // Error: reassignment to val (Fehler: neue Zuweisung zu einem unveränderlichen Wert)
2015-10-16 15:13:49 +03:00
var y = 10
y = 20 // y ist jetzt 20
2015-10-28 10:18:27 +03:00
/*
2017-09-08 13:38:30 +03:00
Scala ist eine statisch getypte Sprache, auch wenn wir in dem o.g. Beispiel
keine Typen an x und y geschrieben haben.
2017-09-08 14:54:54 +03:00
In Scala ist etwas eingebaut, was sich Type Inference nennt. Das heißt, dass der
Scala Compiler in den meisten Fällen erraten kann, von welchem Typ eine Variable ist,
2017-09-08 13:38:30 +03:00
so dass der Typ nicht jedes mal angegeben werden muss.
Einen Typ gibt man bei einer Variablendeklaration wie folgt an:
2015-10-28 10:18:27 +03:00
*/
2015-10-16 15:13:49 +03:00
val z: Int = 10
val a: Double = 1.0
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Bei automatischer Umwandlung von Int auf Double wird aus 10 eine 10.0:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val b: Double = 10
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Boolean-Werte:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
true
false
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Boolean-Operationen:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
!true // false
!false // true
true == false // false
10 > 5 // true
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Mathematische Operationen sind wie gewohnt:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
1 + 1 // 2
2 - 1 // 1
5 * 3 // 15
6 / 2 // 3
6 / 4 // 1
6.0 / 4 // 1.5
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Die Auswertung eines Ausdrucks in der REPL gibt den Typ
2017-09-08 14:54:54 +03:00
// und das Ergebnis zurück:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
scala> 1 + 7
res29: Int = 8
2015-10-28 10:18:27 +03:00
/*
2017-09-08 13:38:30 +03:00
Das bedeutet, dass das Resultat der Auswertung von 1 + 7 ein Objekt
2017-09-08 14:54:54 +03:00
von Typ Int ist und einen Wert 8 hat.
"res29" ist ein sequentiell generierter Name, um das Ergebnis des
2017-09-08 13:38:30 +03:00
Ausdrucks zu speichern. Dieser Wert kann bei Dir anders sein...
2015-10-28 10:18:27 +03:00
*/
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
"Scala strings werden in doppelten Anführungszeichen eingeschlossen"
2017-09-08 14:54:54 +03:00
'a' // Ein Scala Char
// 'Einzeln ge-quotete strings gibt es nicht!' <= Das erzeugt einen Fehler!
2017-09-08 13:38:30 +03:00
2017-09-08 14:54:54 +03:00
// Für Strings gibt es die üblichen Java-Methoden:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
"hello world".length
"hello world".substring(2, 6)
"hello world".replace("C", "3")
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Zusätzlich gibt es noch extra Scala-Methoden
2017-09-08 13:38:30 +03:00
// siehe: scala.collection.immutable.StringOps
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
"hello world".take(5)
"hello world".drop(5)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// String-Interpolation: prefix "s":
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val n = 45
2017-09-08 14:54:54 +03:00
s"Wir haben $n Äpfel" // => "Wir haben 45 Äpfel"
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
2017-09-08 14:54:54 +03:00
// Ausdrücke im Innern von interpolierten Strings gibt es auch:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val a = Array(11, 9, 6)
2017-09-08 14:54:54 +03:00
s"Meine zweite Tochter ist ${a(0) - a(2)} Jahre alt." // => "Meine zweite Tochter ist 5 Jahre alt."
s"Wir haben das Doppelte von ${n / 2.0} an Äpfeln." // => "Wir haben das Doppelte von 22.5 an Äpfeln."
s"2 im Quadrat: ${math.pow(2, 2)}" // => "2 im Quadrat: 4"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Formatierung der interpolierten Strings mit dem prefix "f":
2015-10-28 10:18:27 +03:00
2017-09-08 14:54:54 +03:00
f"5 im Quadrat: ${math.pow(5, 2)}%1.0f" // "5 im Quadrat: 25"
f"Quadratwurzel von 122: ${math.sqrt(122)}%1.4f" // "Quadratwurzel von 122: 11.0454"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Raw Strings ignorieren Sonderzeichen:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
raw"New line feed: \n. Carriage return: \r." // => "New line feed: \n. Carriage return: \r."
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Manche Zeichen müssen "escaped" werden, z.B.
2017-09-08 14:54:54 +03:00
// ein doppeltes Anführungszeichen im Innern eines Strings:
2015-10-28 10:18:27 +03:00
2017-09-08 14:54:54 +03:00
"Sie standen vor der \"Rose and Crown\"" // => "Sie standen vor der "Rose and Crown""
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Dreifache Anführungszeichen erlauben es, dass ein String über mehrere Zeilen geht
2017-09-08 14:54:54 +03:00
// und Anführungszeichen enthalten kann:
2015-10-28 10:18:27 +03:00
2017-09-08 14:54:54 +03:00
val html = """<form id="dieform">
<p>Drück belo', Joe</p>
2015-10-16 15:13:49 +03:00
<input type="submit">
</form>"""
2017-09-08 13:38:30 +03:00
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
// 2. Funktionen
/////////////////////////////////////////////////
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Funktionen werden so definiert:
2017-09-08 13:38:30 +03:00
//
// def functionName(args...): ReturnType = { body... }
//
2017-09-08 14:54:54 +03:00
// Beachte: Es wird hier kein Schlüsselwort "return" verwendet.
// In Scala ist der letzte Ausdruck in einer Funktion der Rückgabewert.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def sumOfSquares(x: Int, y: Int): Int = {
val x2 = x * x
val y2 = y * y
x2 + y2
}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Die geschweiften Klammern können weggelassen werden, wenn
// die Funktion nur aus einem einzigen Ausdruck besteht:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def sumOfSquaresShort(x: Int, y: Int): Int = x * x + y * y
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Syntax für Funktionsaufrufe:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
sumOfSquares(3, 4) // => 25
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// In den meisten Fällen (mit Ausnahme von rekursiven Funktionen) können
// Rückgabetypen auch weggelassen werden, da dieselbe Typ-Inferenz, wie bei
2017-09-08 13:38:30 +03:00
// Variablen, auch bei Funktionen greift:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def sq(x: Int) = x * x // Compiler errät, dass der return type Int ist
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Funktionen können Default-Parameter haben:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def addWithDefault(x: Int, y: Int = 5) = x + y
addWithDefault(1, 2) // => 3
addWithDefault(1) // => 6
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Anonyme Funktionen sehen so aus:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
(x: Int) => x * x
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Im Gegensatz zu def bei normalen Funktionen, kann bei anonymen Funktionen
// sogar der Eingabetyp weggelassen werden, wenn der Kontext klar ist.
// Beachte den Typ "Int => Int", dies beschreibt eine Funktion,
// welche Int als Parameter erwartet und Int zurückgibt.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val sq: Int => Int = x => x * x
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Anonyme Funktionen benutzt man ganz normal:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
sq(10) // => 100
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Wenn ein Parameter einer anonymen Funktion nur einmal verwendet wird,
// bietet Scala einen sehr kurzen Weg diesen Parameter zu benutzen,
// indem die Parameter als Unterstrich "_" in der Parameterreihenfolge
// verwendet werden. Diese anonymen Funktionen werden sehr häufig
// verwendet.
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
val addOne: Int => Int = _ + 1
val weirdSum: (Int, Int) => Int = (_ * 2 + _ * 3)
addOne(5) // => 6
weirdSum(2, 4) // => 16
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Es gibt ein Schlüsselwort "return" in Scala. Allerdings ist seine Verwendung
2017-09-08 13:38:30 +03:00
// nicht immer ratsam und kann fehlerbehaftet sein. "return" gibt nur aus
// dem innersten def, welches den return Ausdruck umgibt, zurück.
// "return" hat keinen Effekt in anonymen Funktionen:
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
def foo(x: Int): Int = {
val anonFunc: Int => Int = { z =>
if (z > 5)
return z // Zeile macht z zum return Wert von foo
else
z + 2 // Zeile ist der return Wert von anonFunc
}
anonFunc(x) // Zeile ist der return Wert von foo
}
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// 3. Flusskontrolle
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// Wertebereiche und Schleifen:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
1 to 5
val r = 1 to 5
r.foreach(println)
r foreach println
(5 to 1 by -1) foreach (println)
2017-09-08 14:54:54 +03:00
// Scala ist syntaktisch sehr großzügig; Semikolons am Zeilenende
2017-09-08 13:38:30 +03:00
// sind optional, beim Aufruf von Methoden können die Punkte
2017-09-08 14:54:54 +03:00
// und Klammern entfallen und Operatoren sind im Grunde austauschbare Methoden.
2017-09-08 13:38:30 +03:00
2017-09-08 14:54:54 +03:00
// while Schleife:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
var i = 0
while (i < 10) { println("i " + i); i += 1 }
i // i ausgeben, res3: Int = 10
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Beachte: while ist eine Schleife im klassischen Sinne -
// Sie läuft sequentiell ab und verändert die loop-Variable.
2017-09-08 14:54:54 +03:00
// "while" in Scala läuft schneller ab als in Java und die o.g.
2017-09-08 13:38:30 +03:00
// Kombinatoren und Zusammenlegungen sind einfacher zu verstehen
2015-10-16 15:13:49 +03:00
// und zu parellelisieren.
2017-09-08 13:38:30 +03:00
// Ein do while Schleife
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
do {
2017-09-08 14:54:54 +03:00
println("x ist immer noch weniger als 10")
2015-10-16 15:13:49 +03:00
x += 1
} while (x < 10)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Endrekursionen sind idiomatisch um sich wiederholende
// Aufgaben in Scala zu lösen. Rekursive Funtionen benötigen explizit einen
// Rückgabe-Typ, der Compiler kann ihn nicht erraten.
// Der Rückgabe-Typ in diesem Beispiel ist Unit:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def showNumbersInRange(a: Int, b: Int): Unit = {
print(a)
if (a < b)
showNumbersInRange(a + 1, b)
}
showNumbersInRange(1, 14)
2015-10-28 10:18:27 +03:00
// Conditionals
2015-10-16 15:13:49 +03:00
val x = 10
if (x == 1) println("yeah")
if (x == 10) println("yeah")
if (x == 11) println("yeah")
if (x == 11) println ("yeah") else println("nay")
println(if (x == 10) "yeah" else "nope")
val text = if (x == 10) "yeah" else "nope"
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// 4. Datenstrukturen (Array, Map, Set, Tuples)
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
// Array
2015-10-16 15:13:49 +03:00
val a = Array(1, 2, 3, 5, 8, 13)
a(0)
a(3)
a(21) // Exception
2015-10-28 10:18:27 +03:00
// Map - Speichert Key-Value-Paare
2017-09-08 14:54:54 +03:00
val m = Map("fork" -> "Gabel", "spoon" -> "Löffel", "knife" -> "Messer")
2015-10-16 15:13:49 +03:00
m("fork")
m("spoon")
m("bottle") // Exception
2017-09-08 14:54:54 +03:00
val safeM = m.withDefaultValue("unbekannt")
2015-10-16 15:13:49 +03:00
safeM("bottle")
2015-10-28 10:18:27 +03:00
// Set - Speichert Unikate, unsortiert (sortiert -> SortedSet)
2015-10-16 15:13:49 +03:00
val s = Set(1, 3, 7)
s(0) //false
s(1) //true
val s = Set(1,1,3,3,7)
s: scala.collection.immutable.Set[Int] = Set(1, 3, 7)
2015-10-28 10:18:27 +03:00
// Tuple - Speichert beliebige Daten und "verbindet" sie miteinander
2017-09-08 13:38:30 +03:00
// Ein Tuple ist keine Collection.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
(1, 2)
(4, 3, 2)
(1, 2, "three")
(a, 2, "three")
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Hier ist der Rückgabewert der Funktion ein Tuple
2017-09-08 14:54:54 +03:00
// Die Funktion gibt das Ergebnis sowie den Rest zurück.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val divideInts = (x: Int, y: Int) => (x / y, x % y)
divideInts(10, 3)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Um die Elemente eines Tuples anzusprechen, benutzt man diese
// Notation: _._n wobei n der index des Elements ist (Index startet bei 1)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val d = divideInts(10, 3)
d._1
d._2
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
// 5. Objektorientierte Programmierung
/////////////////////////////////////////////////
/*
2017-09-08 13:38:30 +03:00
Bislang waren alle gezeigten Sprachelemente einfache Ausdrücke, welche zwar
zum Ausprobieren und Lernen in der REPL gut geeignet sind, jedoch in
2017-09-08 14:54:54 +03:00
einer Scala-Datei selten alleine zu finden sind.
Die einzigen Top-Level-Konstrukte in Scala sind nämlich:
2015-10-28 10:18:27 +03:00
- Klassen (classes)
- Objekte (objects)
- case classes
- traits
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
Diesen Sprachelemente wenden wir uns jetzt zu.
2015-10-28 10:18:27 +03:00
*/
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
// Klassen
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Zum Erstellen von Objekten benötigt man eine Klasse, wie in vielen
// anderen Sprachen auch.
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// erzeugt Klasse mit default Konstruktor:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
class Hund
scala> val t = new Hund
t: Hund = Hund@7103745
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Der Konstruktor wird direkt hinter dem Klassennamen deklariert.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
class Hund(sorte: String)
scala> val t = new Hund("Dackel")
t: Hund = Hund@14be750c
scala> t.sorte //error: value sorte is not a member of Hund
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Per val wird aus dem Attribut ein unveränderliches Feld der Klasse
// Per var wird aus dem Attribut ein veränderliches Feld der Klasse
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
class Hund(val sorte: String)
scala> val t = new Hund("Dackel")
t: Hund = Hund@74a85515
scala> t.sorte
res18: String = Dackel
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Methoden werden mit def geschrieben
2015-10-28 10:18:27 +03:00
2017-09-08 14:54:54 +03:00
def bark = "Wuff, wuff!"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Felder und Methoden können public, protected und private sein
// default ist public
// private ist nur innerhalb des deklarierten Bereichs sichtbar
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
class Hund {
private def x = ...
def y = ...
}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// protected ist nur innerhalb des deklarierten und aller
// erbenden Bereiche sichtbar
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
class Hund {
protected def x = ...
}
class Dackel extends Hund {
// x ist sichtbar
}
2015-10-28 10:18:27 +03:00
// Object
2017-09-08 13:38:30 +03:00
// Wird ein Objekt ohne das Schlüsselwort "new" instanziert, wird das sog.
// "companion object" aufgerufen. Mit dem "object" Schlüsselwort wird so
// ein Objekt (Typ UND Singleton) erstellt. Damit kann man dann eine Klasse
2017-09-08 14:54:54 +03:00
// verwenden, ohne ein Objekt instanziieren zu müssen.
2017-09-08 13:38:30 +03:00
// Ein gültiges companion Objekt einer Klasse ist es aber erst dann, wenn
2017-09-08 14:54:54 +03:00
// es genauso heißt und in derselben Datei wie die Klasse definiert wurde.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
object Hund {
def alleSorten = List("Pitbull", "Dackel", "Retriever")
def createHund(sorte: String) = new Hund(sorte)
}
2015-10-28 10:18:27 +03:00
// Case classes
2017-09-08 14:54:54 +03:00
// Fallklassen bzw. Case classes sind Klassen, die normale Klassen um
// zusätzliche Funktionalität erweitern.
// Mit Case-Klassen bekommt man ein paar
2017-09-08 13:38:30 +03:00
// Dinge einfach dazu, ohne sich darum kümmern zu müssen. Z.B.
// ein companion object mit den entsprechenden Methoden,
// Hilfsmethoden wie toString(), equals() und hashCode() und auch noch
// Getter für unsere Attribute (das Angeben von val entfällt dadurch)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
class Person(val name: String)
class Hund(val sorte: String, val farbe: String, val halter: Person)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Es genügt, das Schlüsselwort case vor die Klasse zu schreiben:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
case class Person(name: String)
case class Hund(sorte: String, farbe: String, halter: Person)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Für neue Instanzen braucht man kein "new":
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val dackel = Hund("dackel", "grau", Person("peter"))
val dogge = Hund("dogge", "grau", Person("peter"))
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
// getter
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
dackel.halter // => Person = Person(peter)
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
// equals
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
dogge == dackel // => false
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
// copy
// otherGeorge == Person("george", "9876")
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val otherGeorge = george.copy(phoneNumber = "9876")
2015-10-28 10:18:27 +03:00
// Traits
2017-09-08 13:38:30 +03:00
// Ähnlich wie Java interfaces, definiert man mit traits einen Objekttyp
// und Methodensignaturen. Scala erlaubt allerdings das teilweise
2017-09-08 14:54:54 +03:00
// Implementieren dieser Methoden. Konstruktorparameter sind nicht erlaubt.
2017-09-08 13:38:30 +03:00
// Traits können von anderen Traits oder Klassen erben, aber nur von
// parameterlosen.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
trait Hund {
def sorte: String
def farbe: String
def bellen: Boolean = true
def beissen: Boolean
}
class Bernhardiner extends Hund{
val sorte = "Bernhardiner"
val farbe = "braun"
def beissen = false
}
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
scala> b
res0: Bernhardiner = Bernhardiner@3e57cd70
scala> b.sorte
res1: String = Bernhardiner
scala> b.bellen
res2: Boolean = true
scala> b.beissen
res3: Boolean = false
2015-10-28 10:18:27 +03:00
// Ein Trait kann auch als Mixin eingebunden werden. Die Klasse erbt vom
// ersten Trait mit dem Schlüsselwort "extends", während weitere Traits
// mit "with" verwendet werden können.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
trait Bellen {
2017-09-08 14:54:54 +03:00
def bellen: String = "Wuff"
2015-10-16 15:13:49 +03:00
}
trait Hund {
def sorte: String
def farbe: String
}
class Bernhardiner extends Hund with Bellen{
val sorte = "Bernhardiner"
val farbe = "braun"
}
scala> val b = new Bernhardiner
b: Bernhardiner = Bernhardiner@7b69c6ba
scala> b.bellen
2017-09-08 14:54:54 +03:00
res0: String = Wuff
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// 6. Mustervergleich (Pattern Matching)
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 13:38:30 +03:00
// Pattern matching in Scala ist ein sehr nützliches und wesentlich
// mächtigeres Feature als Vergleichsfunktionen in Java. In Scala
// benötigt ein case Statement kein "break", ein fall-through gibt es nicht.
// Mehrere Überprüfungen können mit einem Statement gemacht werden.
// Pattern matching wird mit dem Schlüsselwort "match" gemacht.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val x = ...
x match {
case 2 =>
case 3 =>
case _ =>
}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Pattern Matching kann auf beliebige Typen prüfen
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val any: Any = ...
val gleicht = any match {
case 2 | 3 | 5 => "Zahl"
2017-09-08 14:54:54 +03:00
case "wuff" => "String"
2015-10-16 15:13:49 +03:00
case true | false => "Boolean"
case 45.35 => "Double"
case _ => "Unbekannt"
}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// und auf Objektgleichheit
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def matchPerson(person: Person): String = person match {
case Person("George", nummer) => "George! Die Nummer ist " + number
case Person("Kate", nummer) => "Kate! Die Nummer ist " + nummer
case Person(name, nummer) => "Irgendjemand: " + name + ", Telefon: " + nummer
}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Und viele mehr...
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val email = "(.*)@(.*)".r // regex
def matchEverything(obj: Any): String = obj match {
// Werte:
case "Hello world" => "Got the string Hello world"
// Typen:
case x: Double => "Got a Double: " + x
// Conditions:
case x: Int if x > 10000 => "Got a pretty big number!"
// Case Classes:
case Person(name, number) => s"Got contact info for $name!"
// RegEx:
case email(name, domain) => s"Got email address $name@$domain"
// Tuples:
case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c"
// Strukturen:
case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c"
// Patterns kann man ineinander schachteln:
case List(List((1, 2, "YAY"))) => "Got a list of list of tuple"
}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Jedes Objekt mit einer "unapply" Methode kann per Pattern geprüft werden.
// Ganze Funktionen können Patterns sein:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val patternFunc: Person => String = {
case Person("George", number) => s"George's number: $number"
case Person(name, number) => s"Random person's number: $number"
}
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// 7. "Higher-order"-Funktionen
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// Scala erlaubt, dass Methoden und Funktionen wiederum Funtionen und Methoden
// als Aufrufparameter oder Rückgabewert verwenden. Diese Methoden heißen
// higher-order functions.
// Es gibt zahlreiche higher-order-Funtionen nicht nur für Listen, auch für
// die meisten anderen Collection-Typen, sowie andere Klassen in Scala.
// Nennenswerte sind:
// "filter", "map", "reduce", "foldLeft"/"foldRight", "exists", "forall"
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// List
2015-10-28 10:18:27 +03:00
2017-09-08 14:54:54 +03:00
def istGleichVier(a:Int) = a == 4
2015-10-16 15:13:49 +03:00
val list = List(1, 2, 3, 4)
val resultExists4 = list.exists(isEqualToFour)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// map
2017-09-08 13:38:30 +03:00
// map nimmt eine Funktion und führt sie auf jedem Element aus und erzeugt
// eine neue Liste
2015-10-28 10:18:27 +03:00
2017-09-08 14:54:54 +03:00
// Funktion erwartet einen Int und gibt einen Int zurück:
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
val add10: Int => Int = _ + 10
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
2017-09-08 14:54:54 +03:00
// add10 wird auf jedes Element angewendet:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
List(1, 2, 3) map add10 // => List(11, 12, 13)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Anonyme Funktionen können anstatt definierter Funktionen verwendet werden:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
List(1, 2, 3) map (x => x + 10)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Der Unterstrich wird anstelle eines Parameters einer anonymen Funktion
2017-09-08 14:54:54 +03:00
// verwendet. Er wird an die Variable gebunden:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
List(1, 2, 3) map (_ + 10)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Wenn der anonyme Block und die Funktion beide EIN Argument erwarten,
2017-09-08 13:38:30 +03:00
// kann sogar der Unterstrich weggelassen werden.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
List("Dom", "Bob", "Natalia") foreach println
2015-10-28 10:18:27 +03:00
// filter
2017-09-08 13:38:30 +03:00
// filter nimmt ein Prädikat (eine Funktion von A -> Boolean) und findet
2017-09-08 14:54:54 +03:00
// alle Elemente, die auf das Prädikat passen:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
List(1, 2, 3) filter (_ > 2) // => List(3)
case class Person(name: String, age: Int)
List(
Person(name = "Dom", age = 23),
Person(name = "Bob", age = 30)
).filter(_.age > 25) // List(Person("Bob", 30))
2015-10-28 10:18:27 +03:00
// reduce
2017-09-08 13:38:30 +03:00
// reduce nimmt zwei Elemente und kombiniert sie zu einem Element,
2017-09-08 14:54:54 +03:00
// und zwar so lange, bis nur noch ein Element da ist.
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
// foreach
2017-09-08 13:38:30 +03:00
// foreach gibt es für einige Collections
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val aListOfNumbers = List(1, 2, 3, 4, 10, 20, 100)
aListOfNumbers foreach (x => println(x))
aListOfNumbers foreach println
2015-10-28 10:18:27 +03:00
// For comprehensions
2017-09-08 13:38:30 +03:00
// Eine for-comprehension definiert eine Beziehung zwischen zwei Datensets.
// Dies ist keine for-Schleife.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
for { n <- s } yield sq(n)
val nSquared2 = for { n <- s } yield sq(n)
for { n <- nSquared2 if n < 10 } yield n
for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
/////////////////////////////////////////////////
2015-10-28 10:18:27 +03:00
// 8. Implicits
2015-10-16 15:13:49 +03:00
/////////////////////////////////////////////////
2017-09-08 13:38:30 +03:00
// **ACHTUNG:**
2015-10-28 10:18:27 +03:00
// Implicits sind ein sehr mächtiges Sprachfeature von Scala.
2017-09-08 14:54:54 +03:00
// Es sehr einfach,
2017-09-08 13:38:30 +03:00
// sie falsch zu benutzen und Anfänger sollten sie mit Vorsicht oder am
2017-09-08 14:54:54 +03:00
// besten erst dann benutzen, wenn sie verstehen, wie sie funktionieren.
2017-09-08 13:38:30 +03:00
// Dieses Tutorial enthält Implicits, da sie in Scala an jeder Stelle
2017-09-08 14:54:54 +03:00
// vorkommen und man auch mit einer Bibliothek, die Implicits benutzt, sonst
// nichts sinnvolles machen kann.
2017-09-08 13:38:30 +03:00
// Hier soll ein Grundverständnis geschaffen werden, wie sie funktionieren.
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Mit dem Schlüsselwort implicit können Methoden, Werte, Funktion, Objekte
// zu "implicit Methods" werden.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
implicit val myImplicitInt = 100
implicit def myImplicitFunction(sorte: String) = new Hund("Golden " + sorte)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// implicit ändert nicht das Verhalten eines Wertes oder einer Funktion
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
myImplicitInt + 2 // => 102
myImplicitFunction("Pitbull").sorte // => "Golden Pitbull"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Der Unterschied ist, dass diese Werte ausgewählt werden können, wenn ein
// anderer Codeteil einen implicit Wert benötigt, zum Beispiel innerhalb von
// implicit Funktionsparametern
// Diese Funktion hat zwei Parameter: einen normalen und einen implicit
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def sendGreetings(toWhom: String)(implicit howMany: Int) =
s"Hello $toWhom, $howMany blessings to you and yours!"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Werden beide Parameter gefüllt, verhält sich die Funktion wie erwartet
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
sendGreetings("John")(1000) // => "Hello John, 1000 blessings to you and yours!"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 14:54:54 +03:00
// Wird der implicit-Parameter jedoch weggelassen, wird ein anderer
// implicit-Wert vom gleichen Typ genommen. Der Compiler sucht im
// lexikalischen Scope und im companion object nach einem implicit-Wert,
// der vom Typ passt, oder nach einer implicit-Methode, mit der er in den
2017-09-08 13:38:30 +03:00
// geforderten Typ konvertieren kann.
// Hier also: "myImplicitInt", da ein Int gesucht wird
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
sendGreetings("Jane") // => "Hello Jane, 100 blessings to you and yours!"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// bzw. "myImplicitFunction"
2017-09-08 14:54:54 +03:00
// Der String wird erst mit Hilfe der Funktion in Hund konvertiert,
// dann wird die Methode aufgerufen:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
"Retriever".sorte // => "Golden Retriever"
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
2017-09-08 14:54:54 +03:00
// 9. Misc
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
// Importe
2015-10-16 15:13:49 +03:00
import scala.collection.immutable.List
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Importiere alle Unterpackages
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
import scala.collection.immutable._
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Importiere verschiedene Klassen mit einem Statement
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
import scala.collection.immutable.{List, Map}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Einen Import kann man mit '=>' umbenennen
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
import scala.collection.immutable.{List => ImmutableList}
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Importiere alle Klasses, mit Ausnahem von....
// Hier ohne: Map and Set:
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
import scala.collection.immutable.{Map => _, Set => _, _}
2015-10-28 10:18:27 +03:00
2017-09-08 13:38:30 +03:00
// Main
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
object Application {
def main(args: Array[String]): Unit = {
2017-09-08 14:54:54 +03:00
// Zeugs hier rein.
2015-10-16 15:13:49 +03:00
}
}
2015-10-28 10:18:27 +03:00
// I/O
2017-09-08 13:38:30 +03:00
// Eine Datei Zeile für Zeile lesen
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
import scala.io.Source
for(line <- Source.fromFile("myfile.txt").getLines())
println(line)
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
2017-09-08 13:38:30 +03:00
// Eine Datei schreiben
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val writer = new PrintWriter("myfile.txt")
writer.write("Schreibe Zeile" + util.Properties.lineSeparator)
writer.write("Und noch eine Zeile" + util.Properties.lineSeparator)
2015-10-16 15:13:49 +03:00
writer.close()
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
```
2017-09-08 13:38:30 +03:00
## Weiterführende Hinweise
2015-10-16 15:13:49 +03:00
2017-09-08 14:57:12 +03:00
### DE
* [Scala Tutorial](https://scalatutorial.wordpress.com)
* [Scala Tutorial](http://scalatutorial.de)
2017-09-08 14:57:12 +03:00
### EN
2015-10-16 15:13:49 +03:00
* [Scala for the impatient](http://horstmann.com/scala/)
* [Twitter Scala school](http://twitter.github.io/scala_school/)
* [The scala documentation](http://docs.scala-lang.org/)
* [Try Scala in your browser](http://scalatutorials.com/tour/)
* [Neophytes Guide to Scala](http://danielwestheide.com/scala/neophytes.html)
2015-10-17 19:33:54 +03:00
* Join the [Scala user group](https://groups.google.com/forum/#!forum/scala-user)