Salt la conținutul principal
Modulul 5 · Lecția 5 din 525/50 în curs~10 min
Lecții din modul (5/5)

Modelul constructor `Nou...`

Go nu are un cuvânt cheie constructor. Convenția este o fabrică funcție care returnează o valoare sau un pointer inițializat corect. De către nume este de obicei numit NewT (sau NewXxx).

Model de bază: 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)

Beneficii față de literalul direct &User{...}:

  • centralizați validarea și setările implicite.
  • Puteți avea câmpuri neexportate și le puteți popula doar din constructor.
  • Puteți schimba implementarea fără a întrerupe apelanții.

Constructor cu validare: (*T, eroare)

Când inițializarea poate eșua, returnați (*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...
}

Acesta este modelul idiomatic pentru orice constructor cu precondiții: conexiune db, handle de fișier, configurare server etc.

Constructori multipli

Dacă aveți mai multe „căi” de a construi, utilizați nume descriptive:

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

Fără supraîncărcare în Go: numele dezambiguizează.

Opțiuni funcționale (viziune avansată)

Când există mulți parametri opționali, modelul idiomatic este „opțiuni funcționale”:

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

Este mai verbos decât un literal, dar se scalează bine cu multe opționale parametrii și păstrează compatibilitatea cu înapoi (adăugarea unui nou Option nu distruge apelanții existenți).

Când NU aveți nevoie de un constructor

Dacă valoarea zero a tipului este deja utilă, lăsați apelantul să folosească direct literal. Exemplu canonic: sync.Mutex nu are constructor, var m sync.Mutex este deja un mutex gata de utilizare. Același lucru pentru bytes.Buffer.

Regula este: „Fă utilă valoarea zero”. Dacă poți, nu constructor obligatoriu.

Încearcă

Exercițiu#go.m5.l5.e1
Încercări: 0Se încarcă…

Scrieți funcția din fabrică NewUser(șir de nume, vârstă int) *Utilizator care returnează &Utilizator{Nume: nume, Vârstă: vârstă}.

Se încarcă editorul...
Afișează indiciu

Utilizați literalul `&Utilizator{...}` pentru a returna un pointer.

Soluție disponibilă după 3 încercări

Exercițiu#go.m5.l5.e2
Încercări: 0Se încarcă…

Transformați NewUser în (șir de nume) (*Utilizator, eroare): if name == '' return nil, errors.New('nome obligatoriorio').

Se încarcă editorul...
Afișează indiciu

Dacă există precondiții, returnați (*T, eroare) și returnați zero + eroare la eșec.

Soluție disponibilă după 3 încercări

Quiz#go.m5.l5.e3
Gata

Care este convenția idiomatică pentru constructori în Go?

Go
// Which signature is more idiomatic?
Opțiuni de răspuns

Recapitulare

  • Nu constructor: utilizați o funcție NewT (sau New în interiorul pachetului cu același nume).
  • Returnează *T pentru cazul simplu; (*T, error) cu precondiții sau validare.
  • În caz de eroare: returnați nil ca indicator și eroarea explicativă ca a doua valoare.
  • Fara supraincarcare; utilizați nume descriptive (NewUserFromJSON, NewAdmin).
  • „Fă utilă valoarea zero”: dacă poți, constructorul este inutil.
  • Model avansat pentru mulți parametri opționali: opțiuni funcționale.