Scala för backendutveckling och funktionell programmering · Lektion

Smarta konstruktorer

Validerad konstruktion

Lektion 2 av 413 steg

Smarta konstruktorer är en gratis lektion i Scala för backendutveckling och funktionell programmering på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Scala för backendutveckling och funktionell programmering, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Scala för backendutveckling och funktionell programmering innehåller totalt 4 lektioner.

Validerad konstruktion

En smart konstruktor är en fabrik som validerar indata innan den skapar ett värde. Den garanterar att varje instans Ni har uppfyller typens invariants.

  • Den råa konstruktorn är dold.
  • Endast validerad skapelse är offentlig.
class Age private (val value: Int)
object Age:
  def of(v: Int): Option[Age] =
    if v >= 0 then Some(new Age(v)) else None

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

Privat konstruktor

Genom att markera primärkonstruktorn som private hindrar Ni anropare från att kringgå valideringen. Kompanjonobjektet blir den enda ingångspunkten.

class Percentage private (val value: Int)
object Percentage:
  def of(v: Int): Option[Percentage] =
    if v >= 0 && v <= 100 then Some(new Percentage(v)) else None

object Main:
  def main(args: Array[String]): Unit =
    println(Percentage.of(50).map(_.value))
    println(Percentage.of(150))

Returnera Option

Att returnera Option signalerar att konstruktionen kan misslyckas. Anroparen måste hantera None, så ogiltiga data kan aldrig flöda vidare obemärkt.

class NonEmpty private (val value: String)
object NonEmpty:
  def of(s: String): Option[NonEmpty] =
    if s.nonEmpty then Some(new NonEmpty(s)) else None

object Main:
  def main(args: Array[String]): Unit =
    println(NonEmpty.of("").map(_.value))
    println(NonEmpty.of("hi").map(_.value))

Returnera Either för feldetaljer

När Ni vill förklara varför valideringen misslyckades returnerar Ni Either[Error, T]. Left innehåller ett beskrivande meddelande.

class Username private (val value: String)
object Username:
  def of(s: String): Either[String, Username] =
    if s.isEmpty then Left("empty")
    else if s.length > 10 then Left("too long")
    else Right(new Username(s))

object Main:
  def main(args: Array[String]): Unit =
    println(Username.of(""))
    println(Username.of("ada").map(_.value))

Smarta konstruktorer med case class

En case class med privat konstruktor fungerar fortfarande. Observera att dess genererade apply och copy också måste kontrolleras, så definiera en anpassad fabrik och behåll konstruktorn privat.

case class Email private (value: String)
object Email:
  def of(s: String): Option[Email] =
    if s.contains("@") then Some(Email(s)) else None

object Main:
  def main(args: Array[String]): Unit =
    println(Email.of("a@b.com"))
    println(Email.of("bad"))

Kedja validerade värden

Eftersom smarta konstruktorer returnerar Option eller Either kan Ni kombinera dem med for-uttryck för att bygga större validerade objekt.

case class Name private (value: String)
object Name:
  def of(s: String): Option[Name] =
    if s.nonEmpty then Some(Name(s)) else None

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

object Main:
  def make(n: String): Option[Person] =
    for nm <- Name.of(n) yield Person(nm, 20)

  def main(args: Array[String]): Unit =
    println(Main.make("Bob"))

Normalisera indata

En smart konstruktor kan också normalisera data, till exempel genom att ta bort inledande och avslutande blanksteg eller konvertera till gemener, så att alla instanser har ett kanoniskt format.

case class Tag private (value: String)
object Tag:
  def of(s: String): Option[Tag] =
    val clean = s.trim.toLowerCase
    if clean.nonEmpty then Some(Tag(clean)) else None

object Main:
  def main(args: Array[String]): Unit =
    println(Tag.of("  Scala  "))

Invariants gäller för alltid

När ett värde har godkänts av den smarta konstruktorn är dess invariant garanterad under hela dess livstid. Nedströms kod kan lita på värdet utan att kontrollera det igen.

case class PositiveInt private (value: Int)
object PositiveInt:
  def of(n: Int): Option[PositiveInt] =
    if n > 0 then Some(PositiveInt(n)) else None

object Main:
  def doubleIt(p: PositiveInt): Int = p.value * 2 // always positive

  def main(args: Array[String]): Unit =
    PositiveInt.of(5).foreach(p => println(Main.doubleIt(p)))

Kombinera med opaka typer

För validerade värden utan kostnad vid körning kan Ni kombinera en smart konstruktor med en opak typ. Inget wrapper-objekt allokeras, men valideringen styr fortfarande skapandet.

object Domain:
  opaque type Score = Int
  def of(n: Int): Option[Score] =
    if n >= 0 && n <= 100 then Some(n) else None
  extension (s: Score) def value: Int = s

object Main:
  def main(args: Array[String]): Unit =
    println(Domain.of(88).map(_.value))

Flera valideringsregler

Tillämpa flera kontroller i följd. Den första regeln som misslyckas avbryter kedjan och returnerar ett tydligt fel.

object Password:
  def of(s: String): Either[String, String] =
    if s.length < 8 then Left("too short")
    else if !s.exists(_.isDigit) then Left("need a digit")
    else Right(s)

object Main:
  def main(args: Array[String]): Unit =
    println(Password.of("abc"))
    println(Password.of("abcdef12"))

När smarta konstruktorer bör användas

Använd dem när en typ har invariants som rå konstruktion kan bryta mot.

  • Begränsade tal, icke-tomma strängar och formaterade id:n.
  • Returnera Option för ett enkelt ja eller nej, och Either när Ni behöver ange orsaken.
  • Håll den råa konstruktorn privat.
case class Port private (value: Int)
object Port:
  def of(n: Int): Option[Port] =
    if n >= 1 && n <= 65535 then Some(Port(n)) else None

object Main:
  def main(args: Array[String]): Unit =
    println(Port.of(8080))
    println(Port.of(70000))

Snabbtest

Testa Er förståelse av smarta konstruktorer.

Sammanfattning

Ni har lärt Er om smarta konstruktorer.

  • Validera indata i en fabrik i kompanjonobjektet.
  • Gör den råa konstruktorn privat.
  • Returnera Option eller Either för att tvinga fram hantering av fel.
  • Normalisera vid behov indata till ett kanoniskt format.
  • Invariants gäller därefter under hela värdets livstid.
case class Even private (value: Int)
object Even:
  def of(n: Int): Option[Even] =
    if n % 2 == 0 then Some(Even(n)) else None

object Main:
  def main(args: Array[String]): Unit =
    println(Even.of(4))
    println(Even.of(5))
Gratis att börja

Lär dig Scala med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
39
Lektioner
143

Vanliga frågor

Är lektionen ”Smarta konstruktorer” gratis?

Ja – hela texten till ”Smarta konstruktorer” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Scala för backendutveckling och funktionell programmering, kan Ni uppgradera till CoddyKit PRO. Kursen i Scala för backendutveckling och funktionell programmering innehåller totalt 4 lektioner.

Vad lär jag mig i ”Smarta konstruktorer”?

Validerad konstruktion Ni övar på Scala för backendutveckling och funktionell programmering med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Scala för backendutveckling och funktionell programmering?

Du behöver inga förkunskaper. Utbildningen i Scala för backendutveckling och funktionell programmering på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Smarta konstruktorer”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Scala för backendutveckling och funktionell programmering-lektionen?

Ja. Varje Scala för backendutveckling och funktionell programmering-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Modellering med ADT:er
  2. Smarta konstruktorer
  3. Newtypes
  4. Att komponera domäner
← Tillbaka till Scala för backendutveckling och funktionell programmering