Modellering med ADT-er
Gjør ulovlige tilstander umulige å representere
Modellering med ADT-er er en gratis leksjon i Scala for backendutvikling og funksjonell programmering på CoddyKit. Dette er leksjon 1 av 4. 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 4 leksjoner.
Algebraiske datatyper
Algebraiske datatyper (ADT-er) er grunnlaget for funksjonell domenemodellering. De kombinerer produkt- (AND) og sumtyper (OR) for å beskrive data presist.
- Produkt: en post med flere felt.
- Sum: et valg mellom flere varianter.
case class Point(x: Int, y: Int) // product type
object Main:
def main(args: Array[String]): Unit =
println(Point(1, 2))Produktstyper
En produkttype samler verdier. I Scala er en case class et produkt: en instans inneholder alle feltene sine samtidig.
case class User(name: String, age: Int)
object Main:
def main(args: Array[String]): Unit =
val u = User("Ada", 36)
println(u.name)
println(u.age)Sumtyper
En sumtype er en verdi som er nøyaktig én av flere varianter. Enum-er i Scala 3 uttrykker dette direkte.
enum PaymentMethod:
case Cash
case Card(number: String)
case Crypto(wallet: String)
object Main:
def main(args: Array[String]): Unit =
val p: PaymentMethod = PaymentMethod.Card("1234")
println(p)Gjør ugyldige tilstander umulige å representere
Kjerneprinsippet er å utforme typer slik at ugyldige data ikke engang kan konstrueres. Hvis typesystemet forbyr en ugyldig tilstand, trenger De aldri en kontroll av den under kjøring.
enum Connection:
case Disconnected
case Connected(sessionId: String)
object Main:
def main(args: Array[String]): Unit =
// No way to have a sessionId while Disconnected
val c: Connection = Connection.Connected("abc")
println(c)Dårlig design kontra god design
En flat post med nullable felt legger til rette for ugyldige tilstander. Ved å modellere hvert tilfelle som en variant fjernes de.
- Dårlig:
case class Conn(connected: Boolean, sessionId: String)tillater connected=false med en sessionId. - Godt: en sumtype knytter feltet til riktig tilstand.
enum Door:
case Open
case Closed
case Locked(key: String)
object Main:
def main(args: Array[String]): Unit =
val d: Door = Door.Locked("k1")
println(d)Kombinere produkter og summer
Reelle modeller nøster produkter inn i summer og omvendt. Hver variant kan inneholde sitt eget produkt av felt.
case class Address(city: String, zip: String)
enum Contact:
case Email(value: String)
case Postal(address: Address)
object Main:
def main(args: Array[String]): Unit =
val c: Contact = Contact.Postal(Address("Paris", "75001"))
println(c)Mønstermatching på ADT-er
De bruker mønstermatching til å behandle ADT-er. Fordi typen er lukket, varsler kompilatoren hvis De utelater en variant.
enum Shape:
case Circle(r: Double)
case Rect(w: Double, h: Double)
object Main:
def area(s: Shape): Double = s match
case Shape.Circle(r) => 3.14159 * r * r
case Shape.Rect(w, h) => w * h
def main(args: Array[String]): Unit =
println(area(Shape.Rect(2, 3)))Rekursive ADT-er
ADT-er kan referere til seg selv og modellere trær, lister og uttrykk på en naturlig måte.
enum Expr:
case Num(value: Int)
case Add(left: Expr, right: Expr)
object Main:
def eval(e: Expr): Int = e match
case Expr.Num(v) => v
case Expr.Add(l, r) => eval(l) + eval(r)
def main(args: Array[String]): Unit =
val e = Expr.Add(Expr.Num(2), Expr.Num(3))
println(eval(e))Valgfrihet med Option
Bruk Option i stedet for null for å modellere et felt som kanskje ikke finnes. Typen gjør fraværet eksplisitt og tvinger frem håndtering av det.
case class Profile(name: String, nickname: Option[String])
object Main:
def main(args: Array[String]): Unit =
val p = Profile("Grace", None)
println(p.nickname.getOrElse("(none)"))Modellere mengder presist
Unngå primitiv fiksering. I stedet for rå Int- og String-verdier kan De pakke inn meningsfulle mengder, slik at typene dokumenterer hensikten og forhindrer forvekslinger.
case class Quantity(value: Int)
case class Price(cents: Long)
case class LineItem(qty: Quantity, price: Price)
object Main:
def main(args: Array[String]): Unit =
val item = LineItem(Quantity(3), Price(500))
println(item)Hvorfor ADT-er er viktige
ADT-er gir Dem korrekthet og tydelighet.
- Ugyldige tilstander kan ikke bygges.
- Uttømmende matching oppdager manglende tilfeller ved kompilering.
- Datastrukturen dokumenterer domenet.
enum OrderStatus:
case Pending
case Shipped(tracking: String)
case Delivered(at: Long)
object Main:
def main(args: Array[String]): Unit =
val s: OrderStatus = OrderStatus.Shipped("TRK1")
println(s)Kort kontroll
Test forståelsen Deres av ADT-basert modellering.
Oppsummering
De har lært domenemodellering med ADT-er.
- Produkttyper (
case class) kombinerer felt med AND. - Sumtyper (
enum) tilbyr et valg med OR. - Nest dem for å modellere rike domener og rekursive strukturer.
- Bruk
Optioni stedet for null. - Utform modellen slik at ugyldige tilstander ikke kan representeres.
enum Event:
case Created(id: Int)
case Deleted(id: Int, reason: String)
object Main:
def describe(e: Event): String = e match
case Event.Created(id) => s"created $id"
case Event.Deleted(id, reason) => s"deleted $id: $reason"
def main(args: Array[String]): Unit =
println(describe(Event.Deleted(1, "spam")))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 «Modellering med ADT-er» gratis?
Ja – hele teksten i «Modellering med ADT-er» 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 4 leksjoner.
Hva lærer jeg i «Modellering med ADT-er»?
Gjør ulovlige tilstander umulige å representere 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 1 av 4.
Hvor lang tid tar leksjonen «Modellering med ADT-er»?
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
- Modellering med ADT-er
- Smarte konstruktører
- Newtypes
- Sammensetting av domener