Ce face erori (error)
error este o interfață predefinită cu o singură metodă, Error() string. O funcție care poate eșua returnează, ca ultimă valoare, un error: nil înseamnă succes, orice altă valoare descrie problema. Apelantul verifică imediat if err != nil și decide: tratează eroarea, o returnează mai departe sau oprește programul. Go nu are excepții.
Erori simple se creează cu errors.New("mesaj") sau fmt.Errorf("..."). Cu verbul %w, fmt.Errorf împachetează eroarea originală adăugând context, iar errors.Is(err, ErrX) și errors.As(err, &tinta) o găsesc și prin straturile de împachetare.
Erorile cunoscute dinainte se declară ca variabile de pachet (var ErrStocEpuizat = errors.New(...)), iar pentru erori cu date suplimentare se definește un tip propriu cu metoda Error(). Mesajele de eroare se scriu cu literă mică și fără punct la final, pentru că se combină: citire config: deschidere fișier: no such file.
Exemple
Exemplul 1: Returnarea și verificarea erorilor
package main
import (
"errors"
"fmt"
)
var ErrStocEpuizat = errors.New("stoc epuizat")
func comanda(stoc map[string]int, produs string, bucati int) error {
disponibil, ok := stoc[produs]
if !ok {
return fmt.Errorf("produs necunoscut: %q", produs)
}
if bucati > disponibil {
return fmt.Errorf("comanda de %d x %s: %w", bucati, produs, ErrStocEpuizat)
}
stoc[produs] -= bucati
return nil
}
func main() {
stoc := map[string]int{"cafea": 3}
for _, c := range []struct {
produs string
n int
}{{"cafea", 2}, {"ceai", 1}, {"cafea", 5}} {
err := comanda(stoc, c.produs, c.n)
switch {
case err == nil:
fmt.Println("ok, mai sunt", stoc[c.produs])
case errors.Is(err, ErrStocEpuizat):
fmt.Println("reaprovizionare necesară:", err)
default:
fmt.Println("eroare:", err)
}
}
}
Rezultat
ok, mai sunt 1
eroare: produs necunoscut: "ceai"
reaprovizionare necesară: comanda de 5 x cafea: stoc epuizat
Exemplul 2: Tip propriu de eroare și errors.As
errors.As găsește *EroareValidare chiar dacă a fost împachetată cu %w.
package main
import (
"errors"
"fmt"
)
type EroareValidare struct {
Camp string
Motiv string
}
func (e *EroareValidare) Error() string {
return e.Camp + ": " + e.Motiv
}
func valideaza(varsta int) error {
if varsta < 18 {
return &EroareValidare{Camp: "vârsta", Motiv: "trebuie să fie cel puțin 18"}
}
return nil
}
func inregistreaza(nume string, varsta int) error {
if err := valideaza(varsta); err != nil {
return fmt.Errorf("înregistrare %s: %w", nume, err)
}
return nil
}
func main() {
err := inregistreaza("Radu", 16)
fmt.Println(err)
var ev *EroareValidare
if errors.As(err, &ev) {
fmt.Println("câmpul greșit:", ev.Camp)
}
fmt.Println(inregistreaza("Ana", 25))
}
Rezultat
înregistrare Radu: vârsta: trebuie să fie cel puțin 18
câmpul greșit: vârsta
<nil>
Exemplul 3: Erori din biblioteca standard
os.ReadFile returnează o eroare care se poate verifica cu errors.Is(err, fs.ErrNotExist).
package main
import (
"errors"
"fmt"
"io/fs"
"os"
"strconv"
)
func main() {
_, err := os.ReadFile("setari.json")
if errors.Is(err, fs.ErrNotExist) {
fmt.Println("fișierul nu există, folosesc setările implicite")
}
_, err = strconv.Atoi("12a")
fmt.Println(err)
}
Rezultat
fișierul nu există, folosesc setările implicite
strconv.Atoi: parsing "12a": invalid syntax
Greșeli frecvente
- Ignorarea erorii cu
_: programul continuă cu valori greșite. - Compararea mesajelor (
err.Error() == "stoc epuizat"): fragilă. Foloseșteerrors.Iscu o eroare declarată. %vîn loc de%wînfmt.Errorf: eroarea originală se pierde, iarerrors.Isnu o mai găsește.- Returnarea unui pointer
nilde tip concret caerror: interfața nu mai estenil, iarerr != nildevine adevărat. Returnează directnil.
Comenzi înrudite
panic și recover: panic oprește execuția normală pentru erori grave; recover, apelat într-un defer, poate opri panic-ul.if și else: Execută un bloc de cod doar dacă o condiție este adevărată; else tratează cazul contrar.interface și interfețe: Interfața descrie un set de metode; orice tip care le are o implementează automat, fără declarație explicită.type assertion: Scoate valoarea concretă dintr-o interfață: x.(T) verifică dacă interfața ține tipul T și îl returnează.