Scala til backendudvikling og funktionel programmering · Lektion

Smarte konstruktører

Valideret konstruktion

Lektion 2 af 413 trin

Smarte konstruktører er en gratis Scala til backendudvikling og funktionel programmering-lektion på CoddyKit. Dette er lektion 2 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.

Valideret oprettelse

En smart konstruktør er en factory, der validerer input, før den producerer en værdi. Den garanterer, at enhver instans, du har, opfylder typens invariansregler.

  • Den rå konstruktør er skjult.
  • Kun valideret oprettelse er 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 konstruktør

Hvis du markerer den primære konstruktør med private, forhindrer du kaldere i at omgå valideringen. Companion-objektet bliver det eneste indgangspunkt.

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))

Returnering af Option

Returnering af Option signalerer, at oprettelsen kan mislykkes. Kaldere skal håndtere None, så ugyldige data aldrig ubemærket føres videre.

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))

Returnering af Either med fejloplysninger

Når du vil forklare, hvorfor valideringen mislykkedes, skal du returnere Either[Error, T]. Left indeholder en beskrivende meddelelse.

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))

Smart-konstruktører med case class

En case class med en privat konstruktør fungerer stadig. Bemærk, at dens genererede apply og copy også skal styres, så definér en brugerdefineret factory, og hold konstruktøren 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"))

Sammenkædning af validerede værdier

Fordi smart-konstruktører returnerer Option eller Either, kan du komponere dem med for-udtryk for at opbygge større validerede objekter.

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"))

Normalisering af input

En smart-konstruktør kan også normalisere data, for eksempel ved at fjerne mellemrum eller konvertere til små bogstaver, så alle instanser har en kanonisk form.

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  "))

Invariansregler gælder for altid

Når en værdi har bestået den smarte konstruktør, er dens invariansregel garanteret i hele dens levetid. Efterfølgende kode kan stole på værdien uden at kontrollere den 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)))

Kombination med opaque types

Hvis du vil have validerede værdier uden omkostning ved kørsel, kan du kombinere en smart konstruktør med en opaque type. Der allokeres intet indpakningsobjekt, men valideringen styrer stadig oprettelsen.

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))

Flere valideringsregler

Anvend flere kontroller i rækkefølge. Den første regel, der fejler, afbryder forløbet og returnerer en tydelig fejl.

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"))

Hvornår skal du bruge smarte konstruktører

Brug dem, når en type har invariansregler, som en rå oprettelse kan overtræde.

  • Tal inden for et bestemt interval, ikke-tomme strenge og formaterede id'er.
  • Returnér Option ved et simpelt ja/nej-resultat og Either, når du vil angive årsagen.
  • Hold den rå konstruktør 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))

Hurtigt tjek

Test din forståelse af smarte konstruktører.

Opsummering

Du har lært om smarte konstruktører.

  • Validér input i en companion-factory.
  • Gør den rå konstruktør privat.
  • Returnér Option eller Either for at tvinge håndtering af fejl.
  • Normalisér om nødvendigt input til en kanonisk form.
  • Derefter gælder invariansreglerne i hele værdiens levetid.
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 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 “Smarte konstruktører” gratis?

Ja — hele teksten til “Smarte konstruktører” 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 “Smarte konstruktører”?

Valideret konstruktion 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 2 af 4.

Hvor lang tid tager lektionen “Smarte konstruktører”?

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. Modellering med ADT'er
  2. Smarte konstruktører
  3. Newtypes
  4. Sammensætning af domæner
← Tilbage til Scala til backendudvikling og funktionel programmering