Errori sentinella
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 55 di 107.
Un errore sentinella è una variabile di errore predefinita a livello di pacchetto che rappresenta una specifica condizione di errore. A differenza della creazione di nuovi errori ogni volta con errors.New, gli errori sentinella vengono dichiarati una sola volta e riutilizzati in tutto il codice.
Definisci gli errori sentinella come variabili a livello di pacchetto, in genere con nomi che iniziano con Err:
package user
import "errors"
var (
ErrNotFound = errors.New("user not found")
ErrInvalidEmail = errors.New("invalid email address")
ErrDuplicate = errors.New("user already exists")
)Le funzioni restituiscono questi errori predefiniti quando si verificano determinate condizioni:
func FindUser(id int) (*User, error) {
user, exists := users[id]
if !exists {
return nil, ErrNotFound
}
return user, nil
}Il vantaggio degli errori sentinella è che i chiamanti possono verificare condizioni di errore specifiche confrontando direttamente i valori degli errori:
user, err := FindUser(42)
if err == ErrNotFound {
fmt.Println("Creating new user...")
} else if err != nil {
fmt.Println("Unexpected error:", err)
}La libreria standard di Go usa ampiamente gli errori sentinella. Per esempio, io.EOF segnala la fine dell'input e sql.ErrNoRows indica un risultato vuoto della query. Questo schema crea un contratto chiaro tra i pacchetti e chi li usa riguardo agli errori che ci si può aspettare.
Tuttavia, i semplici controlli di uguaglianza non funzionano quando gli errori vengono avvolti. Nella prossima lezione imparerai come errors.Is() risolve questo problema controllando l'intera catena di errori.
Sfida
FacileCostruiamo un sistema di gestione dell'inventario che usa errori sentinella per comunicare condizioni di errore specifiche. Definirai variabili di errore a livello di package che i chiamanti possono controllare per gestire in modo appropriato i diversi casi.
Organizzerai il codice in due file:
inventory.go: crea un sistema di inventario con errori sentinella predefiniti per i casi di errore più comuni.Definisci tre errori sentinella a livello di package:
ErrItemNotFoundcon il messaggio"item not found in inventory"ErrOutOfStockcon il messaggio"item is out of stock"ErrInsufficientQuantitycon il messaggio"insufficient quantity available"
Crea una struct
Inventoryche contiene una mappa dei nomi degli articoli e delle relative quantità. Implementa questi metodi:NewInventory() *Inventory- crea un inventario vuotoAddItem(name string, quantity int)- aggiunge o aggiorna la quantità di un articoloGetQuantity(name string) (int, error)- restituisce la quantità di un articolo oppureErrItemNotFoundse non esistePurchase(name string, quantity int) error- tenta di acquistare gli articoli. RestituisciErrItemNotFoundse l'articolo non esiste,ErrOutOfStockse la quantità attuale è zero oppureErrInsufficientQuantityse la quantità richiesta supera la disponibilità. In caso di successo, riduci la quantità nell'inventario e restituiscinil.
main.go: leggi le operazioni sull'inventario dall'input e mostra come i chiamanti possono controllare errori sentinella specifici usando il confronto diretto di uguaglianza.Leggi dall'input il nome dell'articolo e la quantità da acquistare. Crea un inventario, aggiungi l'articolo
"laptop"con quantità5, quindi tenta l'acquisto. In base all'errore restituito, stampa un messaggio specifico che mostri quale errore sentinella si è verificato.
Verranno forniti i seguenti input:
- Riga 1: nome dell'articolo da acquistare
- Riga 2: quantità da acquistare
Gestisci il risultato controllando quale errore specifico è stato restituito:
- Se
err == ErrItemNotFound: stampaError: Item '[name]' does not exist in our inventory - Se
err == ErrOutOfStock: stampaError: Item '[name]' is currently out of stock - Se
err == ErrInsufficientQuantity: stampaError: Cannot purchase [quantity] units of '[name]' - not enough in stock - In caso di successo: stampa
Successfully purchased [quantity] units of '[name]'
Per esempio, dati laptop e 3, l'output dovrebbe essere:
Successfully purchased 3 units of 'laptop'E dati phone e 2, l'output dovrebbe essere:
Error: Item 'phone' does not exist in our inventoryE dati laptop e 10, l'output dovrebbe essere:
Error: Cannot purchase 10 units of 'laptop' - not enough in stockProvalo tu
package main
import (
"fmt"
)
func main() {
// Leggi l'input
var itemName string
var quantity int
fmt.Scanln(&itemName)
fmt.Scanln(&quantity)
// Crea l'inventario e aggiungi "laptop" con quantità 5
inv := NewInventory()
inv.AddItem("laptop", 5)
// TODO: Prova ad acquistare l'articolo
// Chiama inv.Purchase(itemName, quantity)
// TODO: Controlla quale specifico errore sentinella è stato restituito usando un confronto diretto di uguaglianza
// Usa istruzioni if/else if per verificare:
// - err == ErrItemNotFound
// - err == ErrOutOfStock
// - err == ErrInsufficientQuantity
// - err == nil (operazione riuscita)
// TODO: Stampa il messaggio appropriato in base all'errore
// Se ErrItemNotFound: fmt.Printf("Error: Item '%s' does not exist in our inventory\n", itemName)
// Se ErrOutOfStock: fmt.Printf("Error: Item '%s' is currently out of stock\n", itemName)
// Se ErrInsufficientQuantity: fmt.Printf("Error: Cannot purchase %d units of '%s' - not enough in stock\n", quantity, itemName)
// Se l'operazione riesce: fmt.Printf("Successfully purchased %d units of '%s'\n", quantity, itemName)
}
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
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online