Menu
Coddy logo textTech

Błędy wartownicze

Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 55 z 107.

Błąd wartowniczy to predefiniowana zmienna błędu na poziomie pakietu, która reprezentuje określony warunek błędu. W przeciwieństwie do tworzenia nowych błędów za każdym razem za pomocą errors.New, błędy wartownicze deklaruje się raz i ponownie wykorzystuje w całym kodzie.

Definiujesz błędy wartownicze jako zmienne na poziomie pakietu, zwykle o nazwach zaczynających się od Err:

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

Funkcje zwracają te predefiniowane błędy, gdy wystąpią określone warunki:

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

Zaletą błędów wartowniczych jest to, że wywołujący mogą sprawdzać konkretne warunki błędów, bezpośrednio porównując wartości błędów:

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

Biblioteka standardowa Go intensywnie korzysta z błędów wartowniczych. Na przykład io.EOF sygnalizuje koniec danych wejściowych, a sql.ErrNoRows oznacza pusty wynik zapytania. Ten wzorzec tworzy jasny kontrakt między pakietami a ich użytkownikami dotyczący tego, jakich błędów można się spodziewać.

Jednak proste sprawdzanie równości przestaje działać, gdy błędy są opakowane. W następnej lekcji dowiesz się, jak errors.Is() rozwiązuje ten problem, sprawdzając cały łańcuch błędów.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system zarządzania zapasami, który używa błędów wartowniczych do przekazywania informacji o konkretnych warunkach niepowodzenia. Zdefiniujesz zmienne błędów na poziomie pakietu, które wywołujący mogą sprawdzać, aby odpowiednio obsługiwać różne sytuacje.

Rozmieścisz swój kod w dwóch plikach:

  • inventory.go: Utwórz system zarządzania zapasami z predefiniowanymi błędami wartowniczymi dla typowych przypadków niepowodzenia.

    Zdefiniuj trzy błędy wartownicze na poziomie pakietu:

    • ErrItemNotFound z komunikatem "item not found in inventory"
    • ErrOutOfStock z komunikatem "item is out of stock"
    • ErrInsufficientQuantity z komunikatem "insufficient quantity available"

    Utwórz strukturę Inventory, która przechowuje mapę nazw produktów i ich ilości. Zaimplementuj następujące metody:

    • NewInventory() *Inventory – tworzy pusty magazyn
    • AddItem(name string, quantity int) – dodaje produkt lub aktualizuje jego ilość
    • GetQuantity(name string) (int, error) – zwraca ilość produktu albo ErrItemNotFound, jeśli produkt nie istnieje
    • Purchase(name string, quantity int) error – podejmuje próbę zakupu produktów. Zwróć ErrItemNotFound, jeśli produkt nie istnieje, ErrOutOfStock, jeśli bieżąca ilość wynosi zero, lub ErrInsufficientQuantity, jeśli żądana ilość przekracza dostępny zapas. W przypadku powodzenia zmniejsz zapas i zwróć nil.
  • main.go: Odczytaj z wejścia operacje dotyczące zapasów i pokaż, jak wywołujący mogą sprawdzać konkretne błędy wartownicze za pomocą bezpośredniego porównania równości.

    Odczytaj nazwę produktu i ilość do zakupu z wejścia. Utwórz magazyn, dodaj produkt "laptop" w ilości 5, a następnie podejmij próbę zakupu. Na podstawie zwróconego błędu wyświetl konkretny komunikat informujący, który błąd wartowniczy został rozpoznany.

Dane wejściowe będą następujące:

  • Wiersz 1: Nazwa produktu do kupienia
  • Wiersz 2: Ilość do kupienia

Obsłuż wynik, sprawdzając, który konkretny błąd został zwrócony:

  • Jeśli err == ErrItemNotFound: wyświetl Error: Item '[name]' does not exist in our inventory
  • Jeśli err == ErrOutOfStock: wyświetl Error: Item '[name]' is currently out of stock
  • Jeśli err == ErrInsufficientQuantity: wyświetl Error: Cannot purchase [quantity] units of '[name]' - not enough in stock
  • W przypadku powodzenia: wyświetl Successfully purchased [quantity] units of '[name]'

Na przykład dla danych laptop i 3 wynik powinien wyglądać tak:

Successfully purchased 3 units of 'laptop'

A dla danych phone i 2 wynik powinien wyglądać tak:

Error: Item 'phone' does not exist in our inventory

A dla danych laptop i 10 wynik powinien wyglądać tak:

Error: Cannot purchase 10 units of 'laptop' - not enough in stock

Spróbuj swoich sił

package main

import (
	"fmt"
)

func main() {
	// Odczytaj dane wejściowe
	var itemName string
	var quantity int
	fmt.Scanln(&itemName)
	fmt.Scanln(&quantity)

	// Utwórz magazyn i dodaj "laptop" w ilości 5
	inv := NewInventory()
	inv.AddItem("laptop", 5)

	// TODO: Spróbuj kupić przedmiot
	// Wywołaj inv.Purchase(itemName, quantity)

	// TODO: Sprawdź, który konkretny błąd sygnalizacyjny został zwrócony, używając bezpośredniego porównania równości
	// Użyj instrukcji if/else if, aby sprawdzić:
	// - err == ErrItemNotFound
	// - err == ErrOutOfStock
	// - err == ErrInsufficientQuantity
	// - err == nil (sukces)

	// TODO: Wyświetl odpowiedni komunikat w zależności od błędu
	// Jeśli ErrItemNotFound: fmt.Printf("Error: Item '%s' does not exist in our inventory\n", itemName)
	// Jeśli ErrOutOfStock: fmt.Printf("Error: Item '%s' is currently out of stock\n", itemName)
	// Jeśli ErrInsufficientQuantity: fmt.Printf("Error: Cannot purchase %d units of '%s' - not enough in stock\n", quantity, itemName)
	// Jeśli operacja się powiedzie: fmt.Printf("Successfully purchased %d units of '%s'\n", quantity, itemName)
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Go online