Menu
Coddy logo textTech

Wrapping degli errori (fmt.Errorf)

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 54 di 107.

Quando gli errori attraversano più livelli della tua applicazione, sapere da dove ha avuto origine un errore diventa fondamentale. La funzione fmt.Errorf di Go con il verbo %w ti consente di avvolgere gli errori, preservando l’errore originale e aggiungendo contesto.

L’incapsulamento degli errori crea una catena di errori. Ogni livello può aggiungere informazioni su ciò che stava cercando di fare quando si è verificato l’errore:

func ReadConfig(filename string) error {
    data, err := os.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("reading config file: %w", err)
    }
    // elabora i dati...
    return nil
}

Il verbo %w è speciale. Racchiude l'errore originale all'interno di quello nuovo. È diverso da %v, che si limita a convertire l'errore in una stringa e fa perdere l'identità dell'errore originale.

func LoadSettings() error {
    err := ReadConfig("settings.json")
    if err != nil {
        return fmt.Errorf("loading settings: %w", err)
    }
    return nil
}

Quando LoadSettings fallisce, il messaggio di errore mostra l’intera catena: "loading settings: reading config file: open settings.json: no such file or directory". Ogni livello aggiunge contesto, rendendo il debug molto più semplice.

L’errore avvolto contiene ancora l’errore originale al suo interno. Nella prossima lezione imparerai a svolgere questi errori e a controllare cosa contengono usando errors.Is() e errors.As().

challenge icon

Sfida

Facile

Costruiamo un sistema di elaborazione degli ordini che dimostri come avvolgere gli errori attraverso più livelli. Creerai una catena di funzioni in cui ogni livello aggiunge contesto agli errori, rendendo facile individuare esattamente dove si verificano i problemi.

Organizzerai il codice in due file:

  • orders.go: crea la logica di elaborazione degli ordini con più livelli che avvolgono gli errori mentre risalgono la catena.

    Implementa tre funzioni che formano una catena di elaborazione:

    • ValidateItem(itemID string) error - Restituisce un errore con il messaggio "item not found" se itemID è "INVALID", altrimenti restituisce nil
    • ProcessOrder(orderID, itemID string) error - Chiama ValidateItem. Se restituisce un errore, avvolgilo con il contesto: "processing order [orderID]: %w". Altrimenti restituisci nil
    • SubmitOrder(customerName, orderID, itemID string) error - Chiama ProcessOrder. Se restituisce un errore, avvolgilo con il contesto: "submitting order for [customerName]: %w". Altrimenti restituisci nil

    Ogni livello dovrebbe usare fmt.Errorf con il verbo %w per avvolgere l'errore del livello sottostante, creando una catena di contesto.

  • main.go: leggi i dettagli dell'ordine dall'input, chiama SubmitOrder e mostra il risultato. Se si verifica un errore, stampa l'intera catena di errori. Se l'operazione riesce, stampa un messaggio di conferma.

Verranno forniti i seguenti input:

  • Riga 1: nome del cliente
  • Riga 2: ID dell'ordine
  • Riga 3: ID dell'articolo

Stampa il risultato:

  • Se si verifica un errore: Error: [full error chain]
  • Se l'operazione riesce: Order [orderID] submitted successfully for [customerName]

Ad esempio, con Alice, ORD-123 e INVALID, l'output dovrebbe essere:

Error: submitting order for Alice: processing order ORD-123: item not found

Nota come il messaggio di errore mostri la catena completa. Puoi risalire al problema dal tentativo di invio di livello più alto, passando per l'elaborazione dell'ordine, fino all'effettivo errore di convalida. Ogni livello ha aggiunto il proprio contesto usando %w.

E con Bob, ORD-456 e ITEM-001, l'output dovrebbe essere:

Order ORD-456 submitted successfully for Bob

Provalo tu

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Leggi il nome del cliente
	scanner.Scan()
	customerName := scanner.Text()
	
	// Leggi l'ID dell'ordine
	scanner.Scan()
	orderID := scanner.Text()
	
	// Leggi l'ID dell'articolo
	scanner.Scan()
	itemID := scanner.Text()
	
	// TODO: Chiama SubmitOrder con i valori di input
	// TODO: Se si verifica un errore, stampa: Error: [full error chain]
	// TODO: Se l'operazione riesce, stampa: Order [orderID] submitted successfully for [customerName]
	
	_ = customerName
	_ = orderID
	_ = itemID
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Go online