Scala voor backend-engineering en functioneel programmeren · Les

Union- en intersectietypen

Nieuwe typefuncties

Les 4 van 413 stappen

Union- en intersectietypen is een gratis Scala voor backend-engineering en functioneel programmeren-les op CoddyKit. Dit is les 4 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Scala voor backend-engineering en functioneel programmeren. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Scala voor backend-engineering en functioneel programmeren bevat in totaal 4 lessen.

Nieuwe typefuncties

Scala 3 voegt unietypen (A | B) en intersectietypen (A & B) toe aan het typesysteem. Hiermee kun je waarden nauwkeuriger beschrijven zonder overervingshiërarchieën.

object Main:
  def main(args: Array[String]): Unit =
    println("Union: A | B, Intersection: A & B")

Basisprincipes van unietypen

Een unietype A | B stelt een waarde voor die een A of een B is. Het is een settheoretische OF over typen.

object Main:
  def show(x: Int | String): String = x match
    case i: Int    => s"int $i"
    case s: String => s"str $s"

  def main(args: Array[String]): Unit =
    println(show(42))
    println(show("hi"))

Unietypen hebben geen gemeenschappelijk supertype nodig

In tegenstelling tot Scala 2 Either vereisen unietypen geen wrapper. Je kunt twee willekeurige typen verenigen zonder dat ze dezelfde bovenliggende klasse hebben.

object Main:
  def parse(input: Int | Boolean): String =
    input match
      case n: Int     => s"number $n"
      case b: Boolean => s"flag $b"

  def main(args: Array[String]): Unit =
    println(parse(7))
    println(parse(true))

Unietypen voor foutmodellering

Unietypen zijn handig voor lichtgewicht foutresultaten zonder een wrappertype. In combinatie met enums of singletons zijn ze duidelijk leesbaar.

case object NotFound

object Main:
  def lookup(id: Int): String | NotFound.type =
    if id == 1 then "Alice" else NotFound

  def main(args: Array[String]): Unit =
    println(lookup(1))
    println(lookup(2))

Basisprincipes van intersectietypen

Een intersectietype A & B stelt een waarde voor die zowel A als B is. Het is een settheoretische EN, die vaak wordt gebruikt om traits te combineren.

trait Named:
  def name: String
trait Aged:
  def age: Int

object Main:
  def describe(p: Named & Aged): String =
    s"${p.name} is ${p.age}"

  def main(args: Array[String]): Unit =
    val person = new Named with Aged:
      def name = "Bob"
      def age = 40
    println(describe(person))

Intersectie is commutatief

De volgorde is niet van belang voor intersectietypen: A & B is hetzelfde type als B & A. Dit verschilt van samengestelde typen in Scala 2, zoals A with B, waarbij de volgorde bij het oplossen van sommige leden wel van belang was.

trait Readable:
  def read: String
trait Writable:
  def write(s: String): Unit

object Main:
  def use(r: Readable & Writable): Unit =
    r.write("x")
    println(r.read)

  def main(args: Array[String]): Unit =
    val rw = new Readable with Writable:
      def read = "data"
      def write(s: String) = println(s"wrote $s")
    use(rw)

Meerdere traits combineren

Je kunt meer dan twee typen kruisen. Het resultaat vereist alle vermelde mogelijkheden.

trait A: def a: Int
trait B: def b: Int
trait C: def c: Int

object Main:
  def sum(x: A & B & C): Int = x.a + x.b + x.c

  def main(args: Array[String]): Unit =
    val v = new A with B with C:
      def a = 1
      def b = 2
      def c = 3
    println(sum(v))

Typealiassen voor unietypen

Lange unietypen kun je een naam geven met een type-alias, zodat ondertekeningen leesbaar blijven.

type Json = Int | String | Boolean

object Main:
  def render(j: Json): String = j match
    case i: Int     => i.toString
    case s: String  => s"\"$s\""
    case b: Boolean => b.toString

  def main(args: Array[String]): Unit =
    println(render("hi"))
    println(render(true))

Volledig pattern matchen op unietypen

De compiler kent de leden van een unietype, zodat kan worden gecontroleerd of de afhandeling volledig is. Als je elk alternatief afhandelt, is de match totaal.

type Shape = "circle" | "square"

object Main:
  def sides(s: Shape): Int = s match
    case "circle" => 0
    case "square" => 4

  def main(args: Array[String]): Unit =
    println(sides("square"))

Verbreding van unietypen

Wanneer je een uniewaarde toewijst aan een variabele waarvan het type wordt afgeleid, behoudt Scala het unietype. Houd er rekening mee dat sommige bewerkingen het type verbreden naar de kleinste bovengrens. Gebruik daarom een typeannotatie als je het unietype wilt behouden.

object Main:
  def pick(flag: Boolean): Int | String =
    if flag then 1 else "one"

  def main(args: Array[String]): Unit =
    val x: Int | String = pick(false)
    println(x)

Wanneer gebruik je elk type

Kies het juiste hulpmiddel.

  • Unie: een waarde is een van meerdere typen (OF).
  • Intersectie: een waarde voldoet tegelijk aan meerdere traits (EN).
  • Unies vermijden wrappertypen; intersecties vermijden diepe overerving.
trait Logger: def log(s: String): Unit
trait Clock:  def now: Long

object Main:
  def run(env: Logger & Clock): Unit =
    env.log(s"time=${env.now}")

  def main(args: Array[String]): Unit =
    val env = new Logger with Clock:
      def log(s: String) = println(s)
      def now = 100L
    run(env)

Korte controle

Test je begrip van unie- en intersectietypen.

Samenvatting

Je hebt de unie- en intersectietypen van Scala 3 geleerd.

  • A | B: de waarde is A of B; een wrapper of gemeenschappelijke bovenliggende klasse is niet nodig.
  • A & B: de waarde is zowel A als B; de volgorde is niet van belang.
  • Gebruik pattern matching om unies te verfijnen; combineer traits met intersecties.
  • Gebruik type-aliassen om lange unies een naam te geven.
object Main:
  def length(x: String | List[Int]): Int = x match
    case s: String    => s.length
    case l: List[Int] => l.length

  def main(args: Array[String]): Unit =
    println(length("hello"))
    println(length(List(1, 2, 3)))
Gratis beginnen

Leer Scala met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
39
Lessen
143

Veelgestelde vragen

Is de les “Union- en intersectietypen” gratis?

Ja — de volledige tekst van “Union- en intersectietypen” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Scala voor backend-engineering en functioneel programmeren wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Scala voor backend-engineering en functioneel programmeren bevat in totaal 4 lessen.

Wat leer ik in “Union- en intersectietypen”?

Nieuwe typefuncties Je oefent met Scala voor backend-engineering en functioneel programmeren door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Scala voor backend-engineering en functioneel programmeren te beginnen?

Ervaring vooraf is niet nodig. Scala voor backend-engineering en functioneel programmeren op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.

Hoe lang duurt de les “Union- en intersectietypen”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Scala voor backend-engineering en functioneel programmeren?

Ja. Elke les over Scala voor backend-engineering en functioneel programmeren bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Significante inspringing
  2. Enums in Scala 3
  3. Opaque types
  4. Union- en intersectietypen
← Terug naar Scala voor backend-engineering en functioneel programmeren