Direct naar de hoofdinhoud
Module 5 · Les 5 van 525/50 in de cursus~10 min
Modulelessen (5/5)

Het constructorpatroon 'Nieuw...'

Go heeft geen zoekwoord constructor. De conventie is een fabriek functie die een correct geïnitialiseerde waarde of aanwijzer retourneert. Door naam wordt meestal NewT (of NewXxx) genoemd.

Basispatroon: NewT

Go
type User struct {
    Name string
    Age  int
}

func NewUser(name string, age int) *User {
    return &User{Name: name, Age: age}
}

u := NewUser("Ada", 36)
fmt.Println(u.Name)

Voordelen ten opzichte van de directe letterlijke &User{...}:

  • Je centraliseert validatie en standaardinstellingen.
  • U kunt niet-geëxporteerde velden hebben en deze alleen vanuit de constructor invullen.
  • U kunt de implementatie wijzigen zonder bellers te verbreken.

Constructor met validatie: (*T, fout)

Wanneer initialisatie kan mislukken, retourneert u (*T, error):

Go
import "errors"

func NewUser(name string, age int) (*User, error) {
    if name == "" {
        return nil, errors.New("nome obbligatorio")
    }
    if age < 0 {
        return nil, errors.New("eta non valida")
    }
    return &User{Name: name, Age: age}, nil
}

u, err := NewUser("Ada", 36)
if err != nil {
    // handle...
}

Dit is het idiomatische patroon voor elke constructor met randvoorwaarden: db-verbinding, bestandshandle, serverconfiguratie, etc.

Meerdere constructeurs

Als u meerdere 'manieren' heeft om te construeren, gebruik dan beschrijvende namen:

Go
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }

Geen overbelasting in Go: de naam is ondubbelzinnig.

Functionele opties (geavanceerde blik)

Als er veel optionele parameters zijn, is het idiomatische patroon dat wel "functionele opties":

Go
type Option func(*Server)

func WithPort(p int) Option {
    return func(s *Server) { s.Port = p }
}

func WithTLS(cert, key string) Option {
    return func(s *Server) { s.Cert, s.Key = cert, key }
}

func NewServer(opts ...Option) *Server {
    s := &Server{Port: 8080} // default
    for _, opt := range opts {
        opt(s)
    }
    return s
}

s := NewServer(WithPort(9000), WithTLS("c.pem", "k.pem"))

Het is uitgebreider dan een letterlijke tekst, maar schaalt goed met veel optionele opties parameters en behoudt de achterwaartse compatibiliteit (door een nieuwe Option toe te voegen verbreekt geen bestaande bellers).

Wanneer je GEEN constructor nodig hebt

Als de nulwaarde van het type al nuttig is, laat de beller dan de direct letterlijk. Canonisch voorbeeld: sync.Mutex heeft geen constructor, var m sync.Mutex is al een gebruiksklare mutex. Hetzelfde voor bytes.Buffer.

De regel is: "Maak de nulwaarde nuttig". Als je kunt, nee verplichte constructeur.

Probeer het

Oefening#go.m5.l5.e1
Pogingen: 0Laden…

Schrijf de fabrieksfunctie NewUser(name string, age int) *User die &User{Name: name, Age: age} retourneert.

Editor laden…
Toon hint

Gebruik de letterlijke `&Gebruiker{...}` om een ​​pointer terug te geven.

Oplossing beschikbaar na 3 pogingen

Oefening#go.m5.l5.e2
Pogingen: 0Laden…

Verander NewUser in (naamreeks) (*Gebruiker, fout): if naam == '' retourneer nul, fouten.New('nome obbligatorio').

Editor laden…
Toon hint

Als er voorwaarden zijn, retourneert u (*T, fout) en retourneert u nul + fout bij falen.

Oplossing beschikbaar na 3 pogingen

Quiz#go.m5.l5.e3
Klaar

Wat is de idiomatische conventie voor constructors in Go?

Go
// Which signature is more idiomatic?
Antwoordmogelijkheden

Samenvatten

  • Nee constructor: gebruik een NewT functie (of New in hetzelfde pakket).
  • Retourneer *T voor het eenvoudige geval; (*T, error) met randvoorwaarden of validatie.
  • Bij fout: retourneer nil als aanwijzer en de verklarende fout als tweede waarde.
  • Geen overbelasting; gebruik beschrijvende namen (NewUserFromJSON, NewAdmin).
  • "Maak de nulwaarde nuttig": als je kunt, is de constructor niet nodig.
  • Geavanceerd patroon voor veel optionele parameters: functionele opties.