Lektionen des Moduls (5/5)
Das `New...`-Konstruktormuster
Go hat kein constructor-Schlüsselwort. Die Convention ist eine Fabrik
Funktion, die einen ordnungsgemäß initialisierten Wert oder Zeiger zurückgibt. Von
Der Name lautet normalerweise NewT (oder NewXxx).
Grundmuster: NewT
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)Vorteile gegenüber dem direkten Literal &User{...}:
- Sie zentralisieren Validierung und Standardeinstellungen. – Sie können nicht exportierte Felder haben und diese nur über den Konstruktor füllen.
- Sie können die Implementierung ändern, ohne Anrufer zu unterbrechen.
Konstruktor mit Validierung: (*T, Fehler)
Wenn die Initialisierung fehlschlagen kann, geben Sie (*T, error) zurück:
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...
}Dies ist das idiomatische Muster für jeden Konstruktor mit Voraussetzungen: Datenbankverbindung, Dateihandle, Serverkonfiguration usw.
Mehrere Konstruktoren
Wenn Sie mehrere „Möglichkeiten“ zum Konstruieren haben, verwenden Sie beschreibende Namen:
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }Keine Überladung in Go: Der Name ist eindeutig.
Funktionsoptionen (erweiterte Einblicke)
Wenn viele optionale Parameter vorhanden sind, lautet das idiomatische Muster „Funktionsoptionen“:
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"))Es ist ausführlicher als ein Literal, lässt sich aber gut mit vielen optionalen Elementen skalieren
Parameter und bewahrt die Abwärtskompatibilität (Hinzufügen eines neuen Option
unterbricht bestehende Anrufer nicht).
Wenn Sie KEINEN Konstruktor benötigen
Wenn der Nullwert des Typs bereits nützlich ist, lassen Sie den Aufrufer den verwenden
direktes wörtliches. Kanonisches Beispiel: sync.Mutex hat keinen Konstruktor,
var m sync.Mutex ist bereits ein gebrauchsfertiger Mutex. Das Gleiche gilt für bytes.Buffer.
Die Regel lautet: „Nullwert sinnvoll machen“. Wenn du kannst, nein obligatorischer Konstruktor.
Probieren Sie es aus
Schreiben Sie die Factory-Funktion NewUser(name string, age int) *User, die &User{Name: name, Age: age} zurückgibt.
Hinweis anzeigen
Verwenden Sie das Literal `&User{...}`, um einen Zeiger zurückzugeben.
Lösung nach 3 Versuchen verfügbar
Verwandeln Sie NewUser in (Namenszeichenfolge) (*Benutzer, Fehler): Wenn Name == '' gibt Null zurück, Fehler.New('nome obbligatorio').
Hinweis anzeigen
Wenn Vorbedingungen vorliegen, geben Sie (*T, Fehler) zurück und geben Sie bei einem Fehler Null + Fehler zurück.
Lösung nach 3 Versuchen verfügbar
Was ist die idiomatische Konvention für Konstruktoren in Go?
// Which signature is more idiomatic?Zusammenfassung
- Kein
constructor: Verwenden Sie eineNewT-Funktion (oderNewim gleichnamigen Paket). - Geben Sie
*Tfür den einfachen Fall zurück;(*T, error)mit Vorbedingungen oder Validierung. - Bei Fehler:
nilals Zeiger und den erklärenden Fehler als zweiten Wert zurückgeben. - Keine Überlastung; Verwenden Sie beschreibende Namen (
NewUserFromJSON,NewAdmin). - „Nullwert nützlich machen“: Wenn Sie können, ist der Konstruktor unnötig.
- Erweitertes Muster für viele optionale Parameter: Funktionsoptionen.