Зарегистрируйтесь, чтобы продолжить обучение

Ошибки Основы Go

В Go есть два способа сообщать о проблемах: ошибки и паника.

Ошибки vs исключения

Во многих языках, например, в Python или JavaScript, при возникновении ошибки выбрасывается исключение (exception), которое можно перехватить и обработать. В Go всё иначе: вместо исключений используется явная передача ошибок через возвращаемые значения.

Такой подход делает поток исполнения более прозрачным: вы всегда видите, где может произойти ошибка и как она обрабатывается. Цена за это - постоянные проверки при вызове функций, которые могут вернуть ошибку.

Паника — это ошибки программиста

Go предоставляет механизм паники (panic), но он используется редко. Паника означает, что программа не может продолжать выполнение. Это обычно связано с ошибками в логике программы: выход за границы массива, обращение к nil, нарушение внутренних инвариантов.

Пример паники:

denominator := 0
result := 10 / denominator // Деление на ноль — вызывает панику
fmt.Println("Результат:", result)

Панику можно вызвать явно с помощью функции panic(). Обычно это делается, когда программа сталкивается с ситуацией, которая не должна происходить при корректной логике, и продолжать выполнение небезопасно:

func divide(a, b int) int {
    if b == 0 {
        panic("деление на ноль недопустимо")
    }
    return a / b
}

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

Обработка ошибок

В Go есть специальный тип error, который можно использовать для возврата сообщения об ошибке из функции. Это встроенный тип в стандартной библиотеке, и его удобно использовать для обработки любых проблем, которые могут возникнуть при выполнении функции.

Сигнатура функции, которая может вернуть ошибку, обычно выглядит так:

func имя(аргументы) (результат, error)

Функция divide() ниже возвращает два значения: результат деления и ошибку. Если деление прошло успешно, ошибка равна nil. Если произошла ошибка (например, деление на ноль), вместо результата возвращается 0 и ненулевая ошибка. Вот пример безопасного деления с проверкой деления на ноль:

package main

import (
    "errors"
    "fmt"
)

func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("деление на ноль невозможно")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Ошибка:", err)
        return
    }
    fmt.Println("Результат:", result)
}

Что здесь происходит

  • Функция divide() возвращает два значения: результат и ошибку.
  • Если делитель равен нулю, создаётся ошибка с помощью errors.New.
  • В main() мы проверяем: если err не nil, значит произошла ошибка — выводим её.

Более подробное сообщение об ошибке

Для создания более понятных сообщений можно использовать fmt.Errorf():

return 0, fmt.Errorf("ошибка деления %v / %v: делитель равен нулю", a, b)

Пример: нормальное и ошибочное деление

func main() {
    fmt.Println(divide(12, 4))  // 3 <nil>
    fmt.Println(divide(5, 0))   // 0 ошибка деления 5 / 0: делитель равен нулю
}

Как устроены программы в Go с ошибками

Так как в Go нет исключений и нет конструкции try/catch, весь контроль за ошибками осуществляется через возврат значения типа error. Это приводит к тому, что код часто выглядит как последовательность:

результат, ошибка := функция()
if ошибка != nil {
    // Обработка ошибки
    return ...
}

Такая структура повторяется много раз подряд, что может создать матрешку из вложенных проверок. Поэтому работая с ошибками, принято их выпрямлять:

func process() error {
    data, err := readData()
    if err != nil {
        return err
    }

    value, err := parseData(data)
    if err != nil {
        return err
    }

    result, err := computeResult(value)
    if err != nil {
        return err
    }

    err = saveResult(result)
    if err != nil {
        return err
    }

    fmt.Println("Обработка завершена успешно")
    return nil
}

Дополнительные материалы

  1. Errors

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff