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

841 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"]
2015-10-17 19:33:54 +03:00
filename: learnscala-de.scala
2015-10-16 15:13:49 +03:00
lang: de-de
---
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
der EPFL (Lausanne / Schweiz) unter der Leitung von Martin Odersky entwickelt.
2015-10-28 10:18:27 +03:00
```scala
/*
2015-10-16 15:13:49 +03:00
Scala Umgebung einrichten:
1. Scala binaries herunterladen- http://www.scala-lang.org/downloads
2. Unzip/untar in ein Verzeichnis
3. das bin Unterverzeichnis der `PATH` Umgebungsvariable hinzufügen
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>
Die REPL (Read-Eval-Print Loop) ist der interaktive Scala Interpreter.
Hier kann man jeden Scala Ausdruck verwenden und das Ergebnis wird direkt
ausgegeben.
Als nächstes beschäftigen wir uns mit ein paar Scala Basics.
2015-10-28 10:18:27 +03:00
*/
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
// 1. Basics
/////////////////////////////////////////////////
// Einzeilige Kommentare beginnen mit zwei Slashes
2015-10-16 15:13:49 +03:00
/*
2015-10-28 10:18:27 +03:00
Mehrzeilige Kommentare, starten
mit einem Slash-Stern und enden mit einem Stern-Slash
2015-10-16 15:13:49 +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
// 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
/*
Variablen werden entweder mit var oder val deklariert.
Deklarationen mit val sind immutable, also unveränderlich
Deklarationen mit var sind mutable, also veränderlich
Immutability ist gut.
*/
2015-10-16 15:13:49 +03:00
val x = 10 // x ist 10
x = 20 // error: reassignment to val
var y = 10
y = 20 // y ist jetzt 20
2015-10-28 10:18:27 +03:00
/*
Scala ist eine statisch getypte Sprache, auch wenn wir in dem o.g. Beispiel
2015-10-16 15:13:49 +03:00
keine Typen an x und y geschrieben haben.
2015-10-28 10:18:27 +03:00
In Scala ist etwas eingebaut, was sich Type Inference nennt. Das heißt das der
Scala Compiler in den meisten Fällen erraten kann, von welchen Typ eine Variable ist,
so dass der Typ nicht jedes mal angegeben werden muss.
2015-10-16 15:13:49 +03:00
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
// 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
// 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
// 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
// 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
// Die Auswertung eines Ausdrucks in der REPL gibt den Typ
// 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
/*
2015-10-16 15:13:49 +03:00
Das bedeutet, dass das Resultat der Auswertung von 1 + 7 ein Objekt
von Typ Int ist und einen Wert 0 hat.
"res29" ist ein sequentiell generierter name, um das Ergebnis des
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
"Scala strings werden in doppelten Anführungszeichen eingeschlossen"
'a' // A Scala Char
// 'Einzeln ge-quotete strings gibt es nicht!' <= This causes an error
// 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
// Zusätzlich gibt es noch extra Scala Methoden
// 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
// String interpolation: prefix "s"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val n = 45
s"We have $n apples" // => "We have 45 apples"
2015-10-28 10:18:27 +03:00
// Ausdrücke im Innern von interpolierten Strings gibt es auch
2015-10-16 15:13:49 +03:00
val a = Array(11, 9, 6)
val n = 100
s"My second daughter is ${a(0) - a(2)} years old." // => "My second daughter is 5 years old."
s"We have double the amount of ${n / 2.0} in apples." // => "We have double the amount of 22.5 in apples."
s"Power of 2: ${math.pow(2, 2)}" // => "Power of 2: 4"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
// Formatierung der interpolierten Strings mit dem prefix "f"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
f"Power of 5: ${math.pow(5, 2)}%1.0f" // "Power of 5: 25"
f"Square root of 122: ${math.sqrt(122)}%1.4f" // "Square root of 122: 11.0454"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +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
// Manche Zeichen müssen "escaped" werden, z.B.
// ein doppeltes Anführungszeichen in innern eines Strings.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
"They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown""
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
// Dreifache Anführungszeichen erlauben es, dass ein String über mehrere Zeilen geht
// und Anführungszeichen enthalten kann.
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val html = """<form id="daform">
<p>Press belo', Joe</p>
<input type="submit">
</form>"""
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
// 2. Funktionen
/////////////////////////////////////////////////
2015-10-16 15:13:49 +03:00
// Funktionen werden so definiert
//
// def functionName(args...): ReturnType = { body... }
//
// Beachte: Es gibt kein return Schlüsselwort. 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
// 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
// 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
// In den meisten Fällen (mit Ausnahme von rekursiven Funktionen), können
// Rückgabetypen auch weggelassen werden, da dieselbe Typ Inference, wie bei
// 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
// 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
// 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
// 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
// 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
// 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
2015-10-16 15:13:49 +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
// Es gibt einen keyword return in Scala. Allerdings ist seine Verwendung
// 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
2015-10-16 15:13:49 +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-28 10:18:27 +03:00
/////////////////////////////////////////////////
// 3. Flow Control
/////////////////////////////////////////////////
// Wertebereiche und Schleifen
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)
2015-10-28 10:18:27 +03:00
// Scala ist syntaktisch sehr großzügig, Semikolons am Zeilenende
2015-10-16 15:13:49 +03:00
// sind optional, beim Aufruf von Methoden können die Punkte
// und Klammern entfallen und Operatoren sind im Grunde austauschbare Methoden
// 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
// Beachte: while ist eine Schleife im klassischen Sinne -
// Sie läuft sequentiell ab und verändert die loop-Variable.
// While in Scala läuft schneller ab als in Java und die o.g.
// Kombinatoren und Zusammenlegungen sind einfacher zu verstehen
// und zu parellelisieren.
// Ein do while Schleife
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
do {
println("x ist immer noch weniger wie 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
// Endrekursionen sind ideomatisch um sich wiederholende
// Dinge in Scala zu lösen. Rekursive Funtionen benötigen explizit einen
// return Typ, der Compiler kann ihn nicht erraten.
// Unit, in diesem Beispiel.
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
/////////////////////////////////////////////////
// 4. Daten Strukturen (Array, Map, Set, Tuples)
/////////////////////////////////////////////////
// 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
2015-10-16 15:13:49 +03:00
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
m("fork")
m("spoon")
m("bottle") // Exception
val safeM = m.withDefaultValue("no lo se")
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
2015-10-16 15:13:49 +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
// Hier ist der Rückgabewert der Funktion ein Tuple
// Die Funktion gibt das Ergebnis, so wie 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
// 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
/////////////////////////////////////////////////
/*
Bislang waren alle gezeigten Sprachelemente einfache Ausdrücke, welche zwar
zum Ausprobieren und Lernen in der REPL gut geeignet sind, jedoch in
einem Scala file selten alleine zu finden sind.
Die einzigen Top-Level Konstrukte in Scala sind nämlich:
- Klassen (classes)
- Objekte (objects)
- case classes
- traits
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
Diesen Sprachelemente wenden wir uns jetzt zu.
*/
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
// Zum Erstellen von Objekten benötigt man eine Klasse, wie in vielen
// anderen Sprachen auch.
// 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
// 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
// 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
// Methoden werden mit def geschrieben
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def bark = "Woof, woof!"
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +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
// 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
// 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
// benutzen ohne ein Objekt instanziieren zu müssen.
// Ein gültiges companion Objekt einer Klasse ist es aber erst dann, wenn
// es genauso heisst und in derselben Datei wie die Klasse definiert wurde.
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
// Fallklassen bzw. Case classes sind Klassen die normale Klassen um extra
// Funktionalität erweitern. Mit Case Klassen bekommt man ein paar
// 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-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
// 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
// Für neue Instanzen brauch 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
2015-10-16 15:13:49 +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
2015-10-16 15:13:49 +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
2015-10-16 15:13:49 +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
// Ähnlich wie Java interfaces, definiert man mit traits einen Objekttyp
// und Methodensignaturen. Scala erlaubt allerdings das teilweise
// implementieren dieser Methoden. Konstruktorparameter sind nicht erlaubt.
// Traits können von anderen Traits oder Klassen erben, aber nur von
// parameterlosen.
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
2015-10-16 15:13:49 +03:00
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +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
2015-10-16 15:13:49 +03:00
// Traits können auch via Mixins (Schlüsselwort "with") eingebunden werden
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
trait Bellen {
def bellen: String = "Woof"
}
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
res0: String = Woof
2015-10-28 10:18:27 +03:00
/////////////////////////////////////////////////
// 6. Pattern Matching
/////////////////////////////////////////////////
// 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-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
// 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"
case "woof" => "String"
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
// 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
// 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
// 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
/////////////////////////////////////////////////
// 37. Higher-order functions
/////////////////////////////////////////////////
2015-10-16 15:13:49 +03:00
Scala erlaubt, das Methoden und Funktion wiederum Funtionen und Methoden
als Aufrufparameter oder Return Wert verwenden. Diese Methoden heissen
higher-order functions
Es gibt zahlreiche higher-order functions 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"
## List
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
def isGleichVier(a:Int) = a == 4
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
## map
// map nimmt eine Funktion und führt sie auf jedem Element aus und erzeugt
// eine neue Liste
// Funktion erwartet ein Int und returned ein Int
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +03:00
val add10: Int => Int = _ + 10
2015-10-28 10:18:27 +03:00
2015-10-16 15:13:49 +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
// 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
// Der Unterstrich wird anstelle eines Parameters einer anonymen Funktion
// 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
// Wenn der anonyme Block und die Funtion beide EIN Argument erwarten,
// 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
2015-10-16 15:13:49 +03:00
// filter nimmt ein Prädikat (eine Funktion von A -> Boolean) und findet
// 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
2015-10-16 15:13:49 +03:00
// reduce nimmt zwei Elemente und kombiniert sie zu einem Element,
// und zwar solange bis nur noch ein Element da ist.
2015-10-28 10:18:27 +03:00
// foreach
2015-10-16 15:13:49 +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
2015-10-16 15:13:49 +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
/////////////////////////////////////////////////
2015-10-28 10:18:27 +03:00
// **ACHTUNG:**
// Implicits sind ein sehr mächtiges Sprachfeature von Scala.
// Es sehr einfach
// sie falsch zu benutzen und Anfänger sollten sie mit Vorsicht oder am
// besten erst dann benutzen, wenn man versteht wie sie funktionieren.
// Dieses Tutorial enthält Implicits, da sie in Scala an jeder Stelle
// vorkommen und man auch mit einer Lib die Implicits benutzt nichts sinnvolles
// machen kann.
// Hier soll ein Grundverständnis geschaffen werden, wie sie funktionieren.
2015-10-16 15:13:49 +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
// 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
// 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
// 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
// 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
// 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
// bzw. "myImplicitFunction"
// Der String wird erst mit Hilfe der Funktion in Hund konvertiert, und
// 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
/////////////////////////////////////////////////
// 19. Misc
/////////////////////////////////////////////////
// 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
// 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
// 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
// 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
// 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
// Main
2015-10-16 15:13:49 +03:00
object Application {
def main(args: Array[String]): Unit = {
2015-10-28 10:18:27 +03:00
// Sachen kommen hierhin
2015-10-16 15:13:49 +03:00
}
}
2015-10-28 10:18:27 +03:00
// I/O
2015-10-16 15:13:49 +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
// 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
```
2015-10-17 15:39:21 +03:00
## Weiterführende Hinweise
2015-10-16 15:13:49 +03:00
// DE
* [Scala Tutorial](https://scalatutorial.wordpress.com)
* [Scala Tutorial](http://scalatutorial.de)
// 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)