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)))Rot List(Rot, Gruen, Blau) 2 true 3.14 6.0
Sealed 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))(1 + 2) * 4 12
Option, 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))Right(5) Left(Division durch null) Right(11) Left(DIVISION DURCH NULL) Wert: 4 Success(42) true Fehlgeschlagen: NumberFormatException 14 -1 Some(5) 0
Ausnahmen
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")3 Eigener Fehler: negativ: -2 fertig
Merke
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
Aufgabe
Schreibe einen kleinen Rechner als sealed trait mit Either-Fehlern.