Przejdź do głównej treści
eLearner.app
Moduł 5 · Lekcja 5 z 525/50 w kursie~10 min
Lekcje modułu (5/5)

Wzorzec konstruktora `New...`

Go nie ma słowa kluczowego constructor. Konwencja to fabryka funkcja, która zwraca prawidłowo zainicjowaną wartość lub wskaźnik. Przez nazwa, zwykle nazywa się NewT (lub NewXxx).

Wzór podstawowy: 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)

Korzyści w porównaniu z bezpośrednim dosłownym &User{...}:

  • centralizujesz walidację i ustawienia domyślne.
  • Możesz mieć niewyeksportowane pola i wypełniać je tylko z poziomu konstruktora.
  • Możesz zmienić implementację bez przerywania rozmówców.

Konstruktor z walidacją: (*T, błąd)

Jeśli inicjalizacja może się nie udać, zwróć (*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...
}

Jest to idiomatyczny wzór dla każdego konstruktora warunki wstępne: połączenie z bazą danych, uchwyt pliku, konfiguracja serwera itp.

Wielu konstruktorów

Jeśli masz wiele „sposób” konstruowania, użyj nazw opisowych:

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

Żadnych przeciążeń w Go: nazwa jest jednoznaczna.

Opcje funkcjonalne (zaawansowany podgląd)

Gdy istnieje wiele opcjonalnych parametrów, wzorcem idiomatycznym jest „opcje funkcjonalne”:

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

Jest bardziej szczegółowy niż dosłowny, ale dobrze się skaluje z wieloma opcjonalnymi parametry i zachowuje kompatybilność wsteczną (dodanie nowego Option nie przerywa istniejących rozmówców).

Kiedy NIE potrzebujesz konstruktora

Jeśli wartość zerowa typu jest już użyteczna, pozwól wywołującemu użyć metody bezpośrednie, dosłowne. Przykład kanoniczny: sync.Mutex nie ma konstruktora, var m sync.Mutex jest już gotowym do użycia muteksem. To samo z bytes.Buffer.

Zasada brzmi: „Uczyń wartość zerową użyteczną”. Jeśli możesz, nie obowiązkowy konstruktor.

Spróbuj

Ćwiczenie#go.m5.l5.e1
Próby: 0Ładowanie...

Napisz funkcję fabryczną NewUser(nazwa string, wiek int) *Użytkownik zwracający &User{Nazwa: imię, Wiek: wiek}.

Ładowanie edytora...
Pokaż wskazówkę

Użyj literału `&User{...}`, aby zwrócić wskaźnik.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#go.m5.l5.e2
Próby: 0Ładowanie...

Zamień NewUser na (ciąg nazwy) (*User, błąd): if name == '' zwróć zero, błędy.New('nome obbligatorio').

Ładowanie edytora...
Pokaż wskazówkę

Jeśli istnieją warunki wstępne, zwróć (*T, błąd) i zwróć zero + błąd w przypadku niepowodzenia.

Rozwiązanie dostępne po 3 próbach

Quiz#go.m5.l5.e3
Gotowe

Jaka jest idiomatyczna konwencja dotycząca konstruktorów w Go?

Go
// Which signature is more idiomatic?
Opcje odpowiedzi

Podsumowanie

  • Brak constructor: użyj funkcji NewT (lub New w pakiecie o tej samej nazwie).
  • Zwróć *T dla prostego przypadku; (*T, error) z warunkami wstępnymi lub walidacją.
  • W przypadku błędu: zwróć nil jako wskaźnik i błąd objaśniający jako drugą wartość.
  • Brak przeciążeń; używaj nazw opisowych (NewUserFromJSON, NewAdmin).
  • „Uczyń wartość zerową użyteczną”: jeśli możesz, konstruktor jest niepotrzebny.
  • Zaawansowany wzór dla wielu opcjonalnych parametrów: opcje funkcjonalne.