Go Academy · Lektion

Oprettelse af brugerdefinerede fejl

errors.New, fmt.Errorf og sentinel-fejl

Lektion 2 af 412 trin

Oprettelse af brugerdefinerede fejl er en gratis Go Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Go Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Go Academy-kurset indeholder 4 lektioner i alt.

Hvorfor bruger man tilpassede fejltyper?

Tilpassede fejltyper indeholder strukturerede data ud over en tekstmeddelelse, så kaldere kan undersøge og reagere på bestemte fejltilstande:

package main
import "fmt"

// Custom error type carries extra context
type HTTPError struct {
    StatusCode int
    Message    string
}

func (e *HTTPError) Error() string {
    return fmt.Sprintf("HTTP %d: %s", e.StatusCode, e.Message)
}

func fetch(url string) error {
    return &HTTPError{404, "page not found"}
}

func main() {
    err := fetch("http://example.com")
    fmt.Println(err) // HTTP 404: page not found
}

Implementering af error-grænsefladen

Enhver type med en Error() string-metode opfylder error:

package main
import "fmt"

type ValidationError struct {
    Field   string
    Value   interface{}
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation: field %q value %v — %s", e.Field, e.Value, e.Message)
}

func validateAge(age int) error {
    if age < 0 || age > 150 {
        return &ValidationError{"age", age, "must be between 0 and 150"}
    }
    return nil
}

func main() {
    fmt.Println(validateAge(-5))
}

Sentinelfejl med errors.New

Sentinelfejl er variabler på pakkeniveau for velkendte fejltilstande:

package main
import ("fmt"; "errors")

var (
    ErrNotFound      = errors.New("not found")
    ErrUnauthorized  = errors.New("unauthorized")
    ErrAlreadyExists = errors.New("already exists")
)

func getUser(id int) (string, error) {
    if id != 1 { return "", ErrNotFound }
    return "Alice", nil
}

func main() {
    _, err := getUser(99)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("user does not exist")
    }
}

fmt.Errorf med %w til indpakning

fmt.Errorf med %w pakker en fejl ind og bevarer den oprindelige fejl til errors.Is og errors.As:

package main
import ("fmt"; "errors")

var ErrDatabase = errors.New("database error")

func queryDB() error {
    return fmt.Errorf("queryDB: %w", ErrDatabase)
}

func main() {
    err := queryDB()
    fmt.Println(err)                       // queryDB: database error
    fmt.Println(errors.Is(err, ErrDatabase)) // true — unwrapped
}

Tilpasset fejl med Unwrap

Implementér Unwrap() error på din tilpassede fejltype, så den kan indgå i fejlkæder:

package main
import ("fmt"; "errors")

var ErrNotFound = errors.New("not found")

type QueryError struct {
    Query string
    Err   error
}

func (e *QueryError) Error() string {
    return fmt.Sprintf("query %q: %v", e.Query, e.Err)
}
func (e *QueryError) Unwrap() error { return e.Err }

func main() {
    err := &QueryError{"SELECT *", ErrNotFound}
    fmt.Println(err)
    fmt.Println(errors.Is(err, ErrNotFound)) // true
}

errors.Is — Identitetskontrol

errors.Is gennemgår fejlkæden for at finde en fejl, der er lig med målet:

package main
import ("fmt"; "errors")

var ErrTimeout = errors.New("timeout")

func deepCall() error {
    return fmt.Errorf("layer3: %w", fmt.Errorf("layer2: %w", ErrTimeout))
}

func main() {
    err := deepCall()
    fmt.Println(errors.Is(err, ErrTimeout)) // true — found deep in chain
}

errors.As — Typeudtrækning

errors.As finder den første fejl i kæden, der svarer til en måltype, og tildeler den:

package main
import ("fmt"; "errors")

type PermissionError struct{ User string }
func (e *PermissionError) Error() string { return "permission denied for " + e.User }

func action(user string) error {
    return fmt.Errorf("action: %w", &PermissionError{user})
}

func main() {
    err := action("bob")
    var pe *PermissionError
    if errors.As(err, &pe) {
        fmt.Println("denied:", pe.User) // denied: bob
    }
}

Indpakning af flere fejl (Go 1.20+)

Go 1.20 tilføjede errors.Join og fmt.Errorf med flere %w til sammenføjning af fejl:

package main
import ("fmt"; "errors")

func validate(name, email string) error {
    var errs []error
    if name == ""  { errs = append(errs, errors.New("name required")) }
    if email == "" { errs = append(errs, errors.New("email required")) }
    return errors.Join(errs...)
}

func main() {
    err := validate("", "")
    fmt.Println(err)
    // name required
    // email required
}

Navnekonventioner for fejltyper

Konventioner for fejlvariabler og -typer i Go:

  • Sentinelfejlvariabler: ErrXxx (f.eks. ErrNotFound)
  • Tilpassede fejltyper: XxxError (f.eks. ValidationError)
  • Variabel på pakkeniveau til sentinel-fejl, pointertype til fejl med mange oplysninger
  • Eksportér dem, så kaldere kan bruge dem i errors.Is / errors.As

Hvornår skal du bruge de forskellige metoder?

Sådan vælger du den rette tilgang til fejl:

  • errors.New — enkel fejl uden ekstra data og med kontrol af sentinel-identitet
  • fmt.Errorf — formateret meddelelse med valgfri indpakning
  • Tilpasset type — når kaldere har brug for strukturerede data (felter, koder)
  • errors.Join — samler flere valideringsfejl

Hurtigt tjek

Hvilken funktion gør det muligt at udtrække en bestemt fejltype fra en fejlkæde?

Opsamling: Tilpassede fejl

Opsummering:

  • Implementér Error() string for at oprette tilpassede fejltyper
  • Tilføj Unwrap() error for at indgå i fejlkæder
  • Brug errors.Is til identitetskontrol og errors.As til typeudtrækning
  • Sentinelfejl: ErrXxx; tilpassede typer: XxxError
  • errors.Join samler flere fejl (Go 1.20+)
Gratis at komme i gang

Lær Go 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
51
Lektioner
203

Ofte stillede spørgsmål

Er lektionen “Oprettelse af brugerdefinerede fejl” gratis?

Ja — alle 3 lektioner i læringssporet Go Academy, inklusive “Oprettelse af brugerdefinerede fejl”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Go Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Oprettelse af brugerdefinerede fejl”?

errors.New, fmt.Errorf og sentinel-fejl Du øver dig i Go Academy 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å Go Academy?

Der kræves ingen tidligere erfaring. Go Academy 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 “Oprettelse af brugerdefinerede fejl”?

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 Go Academy-lektion?

Ja. Alle Go Academy-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. interfacet error
  2. Oprettelse af brugerdefinerede fejl
  3. Indpakning og udpakning af fejl
  4. panic, recover og defer
← Tilbage til Go Academy