Kurz: Scala 3 hat echte Enums, auch mit Parametern (algebraische Datentypen):
Teil des Kurses Scala
Enums
Scala 3 hat echte Enums, auch mit Parametern (algebraische Datentypen):
enum Farbe:
case Rot, Gruen, Blau
enum Form:
case Kreis(r: Double)
case Rechteck(b: Double, h: Double)
def flaeche(f: Form): Double = f match
case Form.Kreis(r) => math.Pi * r * r
case Form.Rechteck(b, h) => b * h
@main def main(): Unit =
println(Farbe.Rot)
println(Farbe.values.toList)
println(Farbe.valueOf("Blau").ordinal)
println(Farbe.Gruen == Farbe.Gruen)
println(f"${flaeche(Form.Kreis(1))}%.2f")
println(flaeche(Form.Rechteck(2, 3)))Ausgabe:
Rot
List(Rot, Gruen, Blau)
2
true
3.14
6.0Sealed Traits und Exhaustivität
Bei sealed prüft der Compiler, ob match alle Fälle abdeckt:
sealed trait Ausdruck
case class Zahl(n: Int) extends Ausdruck
case class Plus(a: Ausdruck, b: Ausdruck) extends Ausdruck
case class Mal(a: Ausdruck, b: Ausdruck) extends Ausdruck
def eval(e: Ausdruck): Int = e match
case Zahl(n) => n
case Plus(a, b) => eval(a) + eval(b)
case Mal(a, b) => eval(a) * eval(b)
def zeige(e: Ausdruck): String = e match
case Zahl(n) => n.toString
case Plus(a, b) => s"(${zeige(a)} + ${zeige(b)})"
case Mal(a, b) => s"${zeige(a)} * ${zeige(b)}"
@main def main(): Unit =
val e = Mal(Plus(Zahl(1), Zahl(2)), Zahl(4))
println(zeige(e))
println(eval(e))Ausgabe:
(1 + 2) * 4
12Option, Either und Try
Statt null und Ausnahmen nutzt Scala Werte, die Fehler beschreiben:
import scala.util.{Try, Success, Failure}
def teile(a: Int, b: Int): Either[String, Int] =
if b == 0 then Left("Division durch null") else Right(a / b)
@main def main(): Unit =
println(teile(10, 2))
println(teile(1, 0))
val r = for
x <- teile(100, 5)
y <- teile(x, 2)
yield y + 1
println(r)
println(teile(1, 0).left.map(_.toUpperCase))
println(teile(8, 2).fold(f => s"Fehler: $f", v => s"Wert: $v"))
println(Try("42".toInt))
println(Try("abc".toInt).isFailure)
Try("x".toInt) match
case Success(v) => println(v)
case Failure(e) => println(s"Fehlgeschlagen: ${e.getClass.getSimpleName}")
println(Try("7".toInt).map(_ * 2).getOrElse(-1))
println(Try("q".toInt).getOrElse(-1))
println("5".toIntOption)
println("x".toIntOption.map(_ + 1).getOrElse(0))Ausgabe:
Right(5)
Left(Division durch null)
Right(11)
Left(DIVISION DURCH NULL)
Wert: 4
Success(42)
true
Fehlgeschlagen: NumberFormatException
14
-1
Some(5)
0Ausnahmen
class MeinFehler(msg: String) extends Exception(msg)
def pruefe(n: Int): Int =
if n < 0 then throw MeinFehler(s"negativ: $n")
n
@main def main(): Unit =
try
println(pruefe(3))
println(pruefe(-2))
catch
case e: MeinFehler => println(s"Eigener Fehler: ${e.getMessage}")
case e: Exception => println("anderer Fehler")
finally println("fertig")Ausgabe:
3
Eigener Fehler: negativ: -2
fertigMerke
enumfür Aufzählungen und ADTs,sealedfür Exhaustivitäts-PrüfungOptionfür Fehlendes,Eitherfür Fehler mit Grund,Trykapselt Ausnahmenfor-Comprehensions verketten diese Typen- Ausnahmen mit
try/catch/finallybleiben für Ausnahmefälle
Übungsaufgabe
Schreibe einen kleinen Rechner als sealed trait mit Either-Fehlern.
Quiz zur Selbstkontrolle
Wofür steht sealed?
- Alle Untertypen stehen in derselben Datei, der Compiler prüft match (richtig)
- Die Klasse ist verschlüsselt
- Die Klasse ist final
- Die Klasse ist privat
Wie signalisiert Either einen Fehler?
- Mit Left (richtig)
- Mit Right
- Mit null
- Mit exit
Was gibt "x".toIntOption zurück?
- None (richtig)
- 0
- Eine Exception
- null
Weiter im Kurs
Zurück: Klassen, Traits und Case Classes
Weiter: Generics, Given und Typklassen
Alle Kapitel: Scala im Überblick