Scala til backendudvikling og funktionel programmering · Lektion

Opaque typer

Abstraktioner uden omkostninger

Lektion 3 af 413 trin

Opaque typer er en gratis Scala til backendudvikling og funktionel programmering-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Scala til backendudvikling og funktionel programmering, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Scala til backendudvikling og funktionel programmering-kurset indeholder 4 lektioner i alt.

Hvad er opaque-typer?

Opaque-typer er en funktion i Scala 3 til at oprette abstraktioner uden omkostninger. De giver en særskilt type ved kompilering, men kompileres til den underliggende type uden indpakning ved kørselstid.

  • Typesikkerheden fra en wrapper-klasse.
  • Ingen ekstra allokering.
object Distances:
  opaque type Meters = Double

object Main:
  def main(args: Array[String]): Unit =
    println("Opaque types compile to their underlying type")

Deklaration af en opaque-type

Deklarér en opaque-type i et objekt eller en klasse. Uden for dette scope behandles Meters og Double som forskellige typer.

object Distances:
  opaque type Meters = Double
  def meters(d: Double): Meters = d
  def toDouble(m: Meters): Double = m

object Main:
  def main(args: Array[String]): Unit =
    val d = Distances.meters(5.0)
    println(Distances.toDouble(d))

Opaque-typens grænse

Inden for det scope, hvor typen defineres, kan den opaque type og dens underliggende type bruges om hinanden. Udenfor er kun den opaque type synlig, så du kan ikke ved et uheld sende en rå Double, hvor der kræves Meters.

object Distances:
  opaque type Meters = Double
  def apply(d: Double): Meters = d
  def show(m: Meters): String = s"$m m"

object Main:
  def main(args: Array[String]): Unit =
    val m = Distances(10.0)
    println(Distances.show(m))

Tilføjelse af extension-metoder

Giv opaque-typer funktionalitet med extension-metoder, der defineres i samme scope. Kaldere får praktiske operationer uden at den underliggende type eksponeres.

object Distances:
  opaque type Meters = Double
  def apply(d: Double): Meters = d
  extension (m: Meters)
    def +(other: Meters): Meters = m + other
    def value: Double = m

object Main:
  def main(args: Array[String]): Unit =
    val total = Distances(3.0) + Distances(4.0)
    println(total.value)

Forebyggelse af forvekslinger

Den store fordel er, at to opaque-typer over den samme underliggende type er inkompatible. Meters kan ikke forveksles med Kilometers, selv om begge er Doubles.

object Units:
  opaque type Meters = Double
  opaque type Kilometers = Double
  def m(d: Double): Meters = d
  def km(d: Double): Kilometers = d
  def toMeters(k: Kilometers): Meters = k * 1000

object Main:
  def main(args: Array[String]): Unit =
    val far = Units.km(2.0)
    println(Units.toMeters(far))

Opaque-typer med grænser

Du kan give en opaque-type en øvre grænse med <:. Det eksponerer en del af den offentlige API, mens den præcise repræsentation forbliver skjult.

object Ids:
  opaque type UserId <: Int = Int
  def apply(i: Int): UserId = i

object Main:
  def main(args: Array[String]): Unit =
    val id = Ids(99)
    println(id + 1)

Smart konstruktion med validering

Kombinér opaque types med en validerende factory for at sikre, at værdier altid er gyldige. Konstruktøren forbliver privat; kun den validerede factory er offentlig.

object Ages:
  opaque type Age = Int
  def of(i: Int): Option[Age] =
    if i >= 0 && i < 150 then Some(i) else None
  extension (a: Age) def value: Int = a

object Main:
  def main(args: Array[String]): Unit =
    println(Ages.of(30).map(_.value))
    println(Ages.of(-1))

Ingen omkostning ved kørsel

I modsætning til en value class- eller case class-indpakning opretter en opaque type intet objekt ved kørsel. En List af Meters er bogstaveligt talt en liste af doubles på JVM'en, så der er ingen boxing.

object Temps:
  opaque type Celsius = Double
  def c(d: Double): Celsius = d
  extension (t: Celsius) def value: Double = t

object Main:
  def main(args: Array[String]): Unit =
    val readings = List(Temps.c(20.0), Temps.c(21.5))
    println(readings.map(_.value).sum)

Opaque type kontra typealias

Et almindeligt type X = Y-alias er transparent: X og Y kan bruges fuldstændigt ombytteligt overalt. En opaque type skjuler denne lighed uden for sit scope og giver reel typesikkerhed.

object Demo:
  type Name = String          // transparent alias
  opaque type Email = String  // opaque
  def email(s: String): Email = s
  extension (e: Email) def raw: String = e

object Main:
  def main(args: Array[String]): Unit =
    val e = Demo.email("a@b.com")
    println(e.raw)

Opaque type kontra case class-indpakning

En case class-indpakning som case class Meters(value: Double) giver også typesikkerhed, men allokerer et objekt. Opaque types giver den samme sikkerhed med den rå types ydeevne.

object Money:
  opaque type Cents = Long
  def cents(n: Long): Cents = n
  extension (c: Cents)
    def +(o: Cents): Cents = c + o
    def value: Long = c

object Main:
  def main(args: Array[String]): Unit =
    val total = Money.cents(150) + Money.cents(50)
    println(total.value)

Hvornår skal du bruge opaque types

Brug opaque types, når du ønsker stærk domænetypning i tidskritiske dele af programmet eller i store samlinger.

  • Adskil størrelser som Meters og Seconds.
  • Håndhæv validerede invariansregler.
  • Undgå allokeringsomkostningen ved indpakninger.
object Geo:
  opaque type Latitude = Double
  def lat(d: Double): Option[Latitude] =
    if d >= -90 && d <= 90 then Some(d) else None
  extension (l: Latitude) def value: Double = l

object Main:
  def main(args: Array[String]): Unit =
    println(Geo.lat(41.0).map(_.value))

Hurtigt tjek

Test din forståelse af opaque types.

Opsummering

Du har lært om Scala 3 opaque types.

  • opaque type X = Y skjuler ligheden uden for sit scope.
  • Stil factories og extension-metoder til rådighed som API.
  • Forskellige opaque types baseret på den samme grundtype er inkompatible.
  • Valgfrie øvre begrænsninger med <: eksponerer en delmængde af API'et.
  • Ingen omkostning ved kørsel i modsætning til case class-indpakninger.
object Ids:
  opaque type OrderId = String
  def apply(s: String): OrderId = s
  extension (o: OrderId) def raw: String = o

object Main:
  def main(args: Array[String]): Unit =
    val id = Ids("ORD-1")
    println(id.raw)
Gratis at komme i gang

Lær Scala med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
39
Lektioner
143

Ofte stillede spørgsmål

Er lektionen “Opaque typer” gratis?

Ja — hele teksten til “Opaque typer” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Scala til backendudvikling og funktionel programmering-kurset, skal du opgradere til CoddyKit PRO. Scala til backendudvikling og funktionel programmering-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Opaque typer”?

Abstraktioner uden omkostninger Du øver dig i Scala til backendudvikling og funktionel programmering med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Scala til backendudvikling og funktionel programmering?

Der kræves ingen tidligere erfaring. Scala til backendudvikling og funktionel programmering på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Opaque typer”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Scala til backendudvikling og funktionel programmering-lektion?

Ja. Alle Scala til backendudvikling og funktionel programmering-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Signifikant indentering
  2. Enums i Scala 3
  3. Opaque typer
  4. Forenings- og skæringstyper
← Tilbage til Scala til backendudvikling og funktionel programmering