Scala for backendutvikling og funksjonell programmering · leksjon

Typeklasser og implicits

Lær å bruke typeklasser for ad hoc-polymorfisme og utnytte Scalas implicit-system til kraftige abstraksjoner.

Leksjon 3 av 311 trinn

Typeklasser og implicits er en gratis leksjon i Scala for backendutvikling og funksjonell programmering på CoddyKit. Dette er leksjon 3 av 3. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Scala for backendutvikling og funksjonell programmering, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Scala for backendutvikling og funksjonell programmering inneholder totalt 3 leksjoner.

Ad hoc-polymorfisme forklart

I Scala betyr polymorfisme å skrive kode som fungerer med ulike typer. Du har sett subtypingspolymorfisme med arv, der en metode fungerer for en basisklasse og alle underklassene dens.

Ad hoc-polymorfisme er annerledes. Det lar én enkelt funksjon oppføre seg forskjellig basert på den spesifikke typen den får, selv om typene ikke er beslektet gjennom arv. Det er her typeklasser virkelig kommer til sin rett!

Hva er typeklasser?

En typeklasse er et designmønster som gjør det mulig å legge til ny atferd i eksisterende typer uten å endre dem og uten å bruke arv.

  • Den definerer en kontrakt (en trait) for en bestemt atferd.
  • Den tilbyr «instanser» (objekter) som implementerer denne kontrakten for ulike typer.
  • Den bruker implicit-mekanismen i Scala til automatisk å gjøre riktig atferd tilgjengelig i gjeldende kontekst.

Definere en trait for en typeklasse

Først definerer vi en trait som beskriver atferden vi ønsker. Denne trait-en tar en typeparameter, A, som representerer typen atferden vår skal virke på.

La oss opprette en Printable-typeklasse som vet hvordan en hvilken som helst type kan konverteres til en menneskelesbar streng.

package com.coddykit

trait Printable[A] {
  def format(value: A): String
}

Opprette instanser av typeklasser

Nå må vi fortelle Scala hvordan bestemte typer skal gjøres Printable. Dette gjør vi ved å opprette implicit objects (eller verdier) som utvider Printable-trait-en vår for hver type.

Disse kalles typeklasseinstanser.

package com.coddykit

trait Printable[A] {
  def format(value: A): String
}

object PrintableInstances {
  implicit object StringPrintable extends Printable[String] {
    def format(value: String): String = s"'${value}'"
  }

  implicit object IntPrintable extends Printable[Int] {
    def format(value: Int): String = s"${value}i"
  }
}

Bruke typeklasser med implicits

For å bruke typeklassen vår definerer vi en funksjon som tar en implicit-parameter av typeklassen. Scala-kompilatoren søker automatisk etter en tilgjengelig implicit-instans av Printable[A] når denne funksjonen kalles.

Hvis den finner en, injiserer den instansen i funksjonen!

package com.coddykit

trait Printable[A] {
  def format(value: A): String
}

object PrintableInstances {
  implicit object StringPrintable extends Printable[String] {
    def format(value: String): String = s"'${value}'"
  }

  implicit object IntPrintable extends Printable[Int] {
    def format(value: Int): String = s"${value}i"
  }
}

object PrintableSyntax {
  def print[A](value: A)(implicit p: Printable[A]): Unit = {
    println(p.format(value))
  }
}

object Main {
  import PrintableInstances._
  import PrintableSyntax._

  def main(args: Array[String]): Unit = {
    print("hello")
    print(123)
  }
}

Context bounds: Renere syntaks

Scala tilbyr en kortere syntaks kalt en context bound for implicit-parametere. I stedet for (implicit p: Printable[A]) kan du skrive [A: Printable].

Dette gjør koden ryddigere, særlig når du har flere implicit-parametere.

package com.coddykit

trait Printable[A] {
  def format(value: A): String
}

object PrintableInstances {
  implicit object StringPrintable extends Printable[String] {
    def format(value: String): String = s"'${value}'"
  }

  implicit object IntPrintable extends Printable[Int] {
    def format(value: Int): String = s"${value}i"
  }
}

object PrintableSyntax {
  // Using context bound: [A: Printable] is shorthand for (implicit p: Printable[A])
  def print[A: Printable](value: A): Unit = {
    // To access the implicit instance, use implicitly[Printable[A]]
    val p = implicitly[Printable[A]]
    println(p.format(value))
  }
}

object Main {
  import PrintableInstances._
  import PrintableSyntax._

  def main(args: Array[String]): Unit = {
    print("world")
    print(456)
  }
}

Utvide til egendefinerte typer

Styrken til typeklasser er at du kan legge til ny atferd i alle typer, også typer du ikke eier (som Int eller String), eller dine egne egendefinerte typer, for eksempel case-klasser.

La oss gjøre case-klassen Person vår Printable.

package com.coddykit

trait Printable[A] {
  def format(value: A): String
}

case class Person(name: String, age: Int)

object PrintableInstances {
  implicit object StringPrintable extends Printable[String] {
    def format(value: String): String = s"'${value}'"
  }

  implicit object IntPrintable extends Printable[Int] {
    def format(value: Int): String = s"${value}i"
  }

  // New instance for our custom Person type
  implicit object PersonPrintable extends Printable[Person] {
    def format(person: Person): String = 
      s"Person(name: ${person.name}, age: ${person.age})"
  }
}

object PrintableSyntax {
  def print[A: Printable](value: A): Unit = {
    val p = implicitly[Printable[A]]
    println(p.format(value))
  }
}

object Main {
  import PrintableInstances._
  import PrintableSyntax._

  def main(args: Array[String]): Unit = {
    val alice = Person("Alice", 30)
    print(alice)
  }
}

Implicits: Mer enn typeklasser

Selv om typeklasser er et viktig bruksområde, er nøkkelordet implicit i Scala en bredere mekanisme. Det kan brukes til:

  • Implicit-parametere: Som vi har sett med typeklasser, for å tilby verdier automatisk.
  • Implicit-konverteringer: For automatisk å konvertere én type til en annen (bruk dette med varsomhet, siden det kan gjøre koden vanskeligere å følge).
  • Implicit-verdier: For å tilby standardverdier for bestemte typer, ofte brukt til for eksempel kontekster for kjøring.

Hovedideen er at kompilatoren søker etter passende implicit-definisjoner i gjeldende kontekst.

Fordeler med typeklasser

Typeklasser har flere fordeler:

  • Utvidbarhet: Legg til ny atferd i eksisterende typer uten å endre dem.
  • Avkobling: Skill typedefinisjonen fra atferden dens.
  • Ad hoc-polymorfisme: Funksjoner kan arbeide med alle typer som tilbyr den nødvendige atferden.
  • Testbarhet: Det blir enklere å teste atferd isolert.
  • Ingen kostnader ved arv: Unngå kompleksiteten ved dype arvehierarkier.

Rask sjekk

Se på Printable-typeklassen og instansene dens fra leksjonen. Hvis du kaller print(10.5), hva skjer da, forutsatt at det ikke finnes noen DoublePrintable-instans?

Oppsummering og neste steg

Du har fått full kontroll på typeklasser og Scalas kraftige implicit-system!

  • Typeklasser muliggjør ad hoc-polymorfisme, slik at du kan definere atferd for typer uten arv.
  • De består av en trait (kontrakten) og implicit-objekter/-verdier (instansene).
  • Implicit-parametere og context bounds brukes av funksjoner til automatisk å finne og bruke disse instansene.

Typeklasser er en grunnpilar i funksjonell programmering i Scala og brukes mye i biblioteker som Cats og ZIO for å bygge fleksible og robuste applikasjoner. Fortsett å øve for å styrke forståelsen din!

Gratis å komme i gang

Lær deg Scala med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
39
Leksjoner
143

Ofte stilte spørsmål

Er leksjonen «Typeklasser og implicits» gratis?

Ja – hele teksten i «Typeklasser og implicits» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Scala for backendutvikling og funksjonell programmering-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Scala for backendutvikling og funksjonell programmering inneholder totalt 3 leksjoner.

Hva lærer jeg i «Typeklasser og implicits»?

Lær å bruke typeklasser for ad hoc-polymorfisme og utnytte Scalas implicit-system til kraftige abstraksjoner. Du øver på Scala for backendutvikling og funksjonell programmering med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Scala for backendutvikling og funksjonell programmering?

Ingen tidligere erfaring er nødvendig. Scala for backendutvikling og funksjonell programmering på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 3.

Hvor lang tid tar leksjonen «Typeklasser og implicits»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Scala for backendutvikling og funksjonell programmering-leksjonen?

Ja. Alle Scala for backendutvikling og funksjonell programmering-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Generiske typer og typeparametere
  2. Varians: kovarians og kontravarians
  3. Typeklasser og implicits
← Tilbake til Scala for backendutvikling og funksjonell programmering