Menu
Coddy logo textTech

Интерфейс error

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 52 из 107.

В Go обработка errors выполняется через встроенный interface с именем error. Этот interface необычайно прост. Он требует всего один метод:

type error interface {
    Error() string
}

Любой тип, реализующий метод Error(), возвращающий строку, автоматически удовлетворяет интерфейсу error. Так работает система интерфейсов Go: явное объявление не требуется.

Самый распространённый способ создавать ошибки — использовать пакет 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
}

Функции Go обычно возвращают ошибку в качестве последнего возвращаемого значения. Если ошибки не происходит, возвращается nil. Затем вызывающий код проверяет, что ошибка не равна nil, прежде чем продолжить:

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

Вы также можете использовать fmt.Errorf, чтобы создавать форматированные сообщения об ошибках:

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

Этот шаблон возврата ошибок вместо выбрасывания исключений является фундаментальным для Go. Он делает обработку ошибок явной и заставляет вас задуматься о том, что происходит, когда что-то идёт не так: это ключевой аспект написания надёжного объектно-ориентированного кода.

challenge icon

Задание

Легко

Создадим систему банковского счёта, демонстрирующую способ обработки ошибок в Go. Ты создашь простой счёт, который проверяет операции и возвращает понятные ошибки, когда что-то идёт не так.

Ты организуешь код в двух файлах:

  • account.go: Создай структуру BankAccount с экспортируемым полем Owner (string) и неэкспортируемым полем balance (float64). Реализуй следующее:
    • NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error) — конструктор, который возвращает ошибку с сообщением "initial deposit must be positive", если initial deposit равен нулю или отрицателен. В противном случае создай и верни счёт.
    • Deposit(amount float64) error — добавляет деньги к balance. Возвращай ошибку с сообщением "deposit amount must be positive", если amount равен нулю или отрицателен.
    • Withdraw(amount float64) error — снимает деньги с balance. Возвращай ошибку с сообщением "withdrawal amount must be positive", если amount равен нулю или отрицателен, или "insufficient funds", если balance меньше суммы снятия.
    • Balance() float64 — возвращает текущее значение balance
  • main.go: Считай данные счёта и суммы операций из входных данных. Попробуй создать счёт и выполнить операции. После каждой операции выведи либо сообщение об успешном выполнении, либо сообщение об ошибке.

Будут предоставлены следующие входные данные:

  • Line 1: имя владельца
  • Line 2: сумма initial deposit
  • Line 3: сумма Deposit
  • Line 4: сумма снятия

Для каждой операции выведи результат:

  • После создания счёта: Account created for [Owner] with balance: $[balance] или Error: [error message]
  • После Deposit: Deposited successfully. New balance: $[balance] или Error: [error message]
  • После снятия: Withdrew successfully. New balance: $[balance] или Error: [error message]

Форматируй все значения balance с двумя десятичными знаками. Если создание счёта завершится ошибкой, пропусти остальные операции.

Например, если заданы Alice, 100, 50 и 200, результатом должен быть:

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

А если заданы Bob, -50, 25 и 10, результатом должен быть:

Error: initial deposit must be positive

Попробуйте сами

package main

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

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

	// Прочитать имя владельца
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)

	// Read initial deposit
	initialDepositStr, _ := reader.ReadString('\n')
	initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)

	// Read deposit amount
	depositStr, _ := reader.ReadString('\n')
	depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)

	// Read withdrawal amount
	withdrawStr, _ := reader.ReadString('\n')
	withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)

	// TODO: Создать новый банковский счёт с помощью NewBankAccount
	// Если возникает ошибка, вывести "Error: [error message]" и вернуться
	// Если успешно, вывести "Account created for [Owner] with balance: $[balance]"

	// TODO: Попытаться внести сумму депозита
	// Если возникает ошибка, вывести "Error: [error message]"
	// If successful, print "Deposited successfully. New balance: $[balance]"

	// TODO: Попытаться снять сумму снятия
	// Если возникает ошибка, вывести "Error: [error message]"
	// If successful, print "Withdrew successfully. New balance: $[balance]"

	// Не забудьте форматировать значения баланса с двумя десятичными знаками, используя fmt.Printf("%.2f", balance)

	_ = ownerName
	_ = initialDeposit
	_ = depositAmount
	_ = withdrawAmount
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Go