Menu
Coddy logo textTech

Interfejs błędu

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

W Go błędy są obsługiwane za pomocą wbudowanego interfejsu o nazwie error. Ten interfejs jest wyjątkowo prosty. Wymaga tylko jednej metody:

type error interface {
    Error() string
}

Każdy typ, który implementuje metodę Error() zwracającą ciąg znaków, automatycznie spełnia interfejs error. Tak działa system interfejsów w Go: nie jest potrzebna jawna deklaracja.

Najczęstszym sposobem tworzenia błędów jest użycie pakietu errors:

import "errors"

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

Funkcje w Go zwykle zwracają błąd jako ostatnią wartość zwracaną. Gdy nie wystąpi błąd, zwracasz nil. Następnie wywołujący sprawdza, czy błąd jest różny od nil, zanim będzie kontynuować:

result, err := Divide(10, 0)
if err != nil {
    fmt.Println("Error:", err.Error())
    return
}
fmt.Println("Result:", result)

Możesz również użyć fmt.Errorf, aby tworzyć sformatowane komunikaty o błędach:

func GetUser(id int) (string, error) {
    if id <= 0 {
        return "", fmt.Errorf("invalid user id: %d", id)
    }
    return "Alice", nil
}

Ten wzorzec zwracania błędów zamiast zgłaszania wyjątków jest fundamentalny dla Go. Sprawia, że obsługa błędów jest jawna, i zmusza cię do zastanowienia się, co się dzieje, gdy coś pójdzie nie tak — to kluczowy aspekt pisania odpornego kodu obiektowego.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system konta bankowego, który demonstruje sposób obsługi błędów w Go. Utworzysz proste konto, które weryfikuje operacje i zwraca zrozumiałe błędy, gdy coś pójdzie nie tak.

Rozmieścisz kod w dwóch plikach:

  • account.go: Utwórz strukturę BankAccount z eksportowanym polem Owner (string) i nieeksportowanym polem balance (float64). Zaimplementuj następujące elementy:
    • NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error) — konstruktor, który zwraca błąd z komunikatem "initial deposit must be positive", jeśli początkowa wpłata wynosi zero lub jest ujemna. W przeciwnym razie utwórz i zwróć konto.
    • Deposit(amount float64) error — dodaje pieniądze do salda. Zwróć błąd z komunikatem "deposit amount must be positive", jeśli kwota wynosi zero lub jest ujemna.
    • Withdraw(amount float64) error — odejmuje pieniądze od salda. Zwróć błąd z komunikatem "withdrawal amount must be positive", jeśli kwota wynosi zero lub jest ujemna, albo "insufficient funds", jeśli saldo jest niższe niż kwota wypłaty.
    • Balance() float64 — zwraca bieżące saldo
  • main.go: Odczytaj z wejścia dane konta i kwoty transakcji. Spróbuj utworzyć konto i wykonać operacje. Po każdej operacji wypisz komunikat o powodzeniu albo komunikat o błędzie.

Podane zostaną następujące dane wejściowe:

  • Wiersz 1: Imię właściciela
  • Wiersz 2: Kwota początkowej wpłaty
  • Wiersz 3: Kwota wpłaty
  • Wiersz 4: Kwota wypłaty

Wypisz wynik każdej operacji:

  • Po utworzeniu konta: Account created for [Owner] with balance: $[balance] lub Error: [error message]
  • Po wpłacie: Deposited successfully. New balance: $[balance] lub Error: [error message]
  • Po wypłacie: Withdrew successfully. New balance: $[balance] lub Error: [error message]

Formatuj wszystkie wartości salda z dokładnością do dwóch miejsc po przecinku. Jeśli utworzenie konta się nie powiedzie, pomiń pozostałe operacje.

Na przykład dla danych Alice, 100, 50 i 200 wynik powinien wyglądać następująco:

Account created for Alice with balance: $100.00
Deposited successfully. New balance: $150.00
Error: insufficient funds

A dla danych Bob, -50, 25 i 10 wynik powinien wyglądać następująco:

Error: initial deposit must be positive

Spróbuj swoich sił

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Wczytaj imię i nazwisko właściciela
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)

	// Wczytaj wpłatę początkową
	initialDepositStr, _ := reader.ReadString('\n')
	initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)

	// Wczytaj kwotę wpłaty
	depositStr, _ := reader.ReadString('\n')
	depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)

	// Wczytaj kwotę wypłaty
	withdrawStr, _ := reader.ReadString('\n')
	withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)

	// TODO: Utwórz nowe konto bankowe za pomocą NewBankAccount
	// Jeśli wystąpi błąd, wypisz "Error: [error message]" i zakończ działanie
	// Jeśli operacja się powiedzie, wypisz "Account created for [Owner] with balance: $[balance]"

	// TODO: Spróbuj wpłacić podaną kwotę
	// Jeśli wystąpi błąd, wypisz "Error: [error message]"
	// Jeśli operacja się powiedzie, wypisz "Deposited successfully. New balance: $[balance]"

	// TODO: Spróbuj wypłacić podaną kwotę
	// Jeśli wystąpi błąd, wypisz "Error: [error message]"
	// Jeśli operacja się powiedzie, wypisz "Withdrew successfully. New balance: $[balance]"

	// Pamiętaj, aby formatować saldo do dwóch miejsc po przecinku za pomocą fmt.Printf("%.2f", balance)

	_ = ownerName
	_ = initialDeposit
	_ = depositAmount
	_ = withdrawAmount
}
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