EMZETT.
Login

Kurz: class Kiste[A](val inhalt: A): def map[B](f: A => B): Kiste[B] = Kiste(f(inhalt)) override def toString = s”Kiste($inhalt)”

Teil des Kurses Scala

Kapitel 6 von 8 im Kurs Scala (Abschnitt „Fortgeschritten“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Generics

def zweimal[A](x: A): List[A] = List(x, x)
 
class Kiste[A](val inhalt: A):
  def map[B](f: A => B): Kiste[B] = Kiste(f(inhalt))
  override def toString = s"Kiste($inhalt)"
 
def groesster[A](l: List[A])(using ord: Ordering[A]): A = l.reduce((a, b) => if ord.gt(a, b) then a else b)
 
@main def main(): Unit =
  println(zweimal("hi"))
  println(Kiste(21).map(_ * 2))
  println(groesster(List(3, 8, 5)))
  println(groesster(List("b", "z", "a")))

Ausgabe:

List(hi, hi)
Kiste(42)
8
z

Funktionen höherer Ordnung und Currying

def addiere(a: Int)(b: Int): Int = a + b
val plus5 = addiere(5)
val verkette = (f: Int => Int, g: Int => Int) => f.andThen(g)
 
@main def main(): Unit =
  println(plus5(10))
  println(addiere(1)(2))
  val f = verkette(_ + 1, _ * 10)
  println(f(4))
  val teilweise: Int => Int = math.max(3, _)
  println(List(1, 5, 2).map(teilweise))
  val zaehler = { var n = 0; () => { n += 1; n } }
  println((zaehler(), zaehler(), zaehler()))

Ausgabe:

15
3
50
List(3, 5, 3)
(1,2,3)

Given und Using (Typklassen)

Typklassen erlauben neues Verhalten für bestehende Typen:

trait Beschreibbar[A]:
  def beschreibe(a: A): String
 
given Beschreibbar[Int] with
  def beschreibe(a: Int) = s"Zahl $a"
 
given Beschreibbar[String] with
  def beschreibe(a: String) = s"Text '$a'"
 
given [A](using b: Beschreibbar[A]): Beschreibbar[List[A]] with
  def beschreibe(l: List[A]) = l.map(b.beschreibe).mkString("[", ", ", "]")
 
def zeige[A](a: A)(using b: Beschreibbar[A]): String = b.beschreibe(a)
 
@main def main(): Unit =
  println(zeige(5))
  println(zeige("hi"))
  println(zeige(List(1, 2)))

Ausgabe:

Zahl 5
Text 'hi'
[Zahl 1, Zahl 2]

Extension Methods

extension (s: String)
  def istPalindrom: Boolean = s == s.reverse
  def wiederhole(n: Int): String = s * n
 
extension [A](l: List[A])
  def zweites: Option[A] = l.lift(1)
 
@main def main(): Unit =
  println("anna".istPalindrom)
  println("ab".wiederhole(3))
  println(List(1, 2, 3).zweites)
  println(List(1).zweites)

Ausgabe:

true
ababab
Some(2)
None

Opaque Types und Union Types

object Typen:
  opaque type Meter = Double
  object Meter:
    def apply(d: Double): Meter = d
  extension (m: Meter)
    def wert: Double = m
    def +(o: Meter): Meter = m + o
 
def zeige(x: Int | String): String = x match
  case i: Int => s"Int $i"
  case s: String => s"String $s"
 
@main def main(): Unit =
  import Typen.*
  println((Meter(1.5) + Meter(2)).wert)
  println(zeige(3))
  println(zeige("a"))

Ausgabe:

3.5
Int 3
String a

Merke

  • Generics [A], Kontextparameter mit using und Instanzen mit given
  • Typklassen = Trait + given-Instanzen
  • extension fügt Methoden zu bestehenden Typen hinzu
  • opaque type und Union Types (A | B) sind neu in Scala 3

Übungsaufgabe

Schreibe eine Typklasse Ordnung[A] mit Instanzen für Int und String.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Enums, ADTs und Fehlerbehandlung

Weiter: Nebenläufigkeit und Ökosystem

Alle Kapitel: Scala im Überblick