Должен ли я использовать панику или ошибку возврата?

Go предоставляет два способа обработки ошибок, но я не уверен, какой из них использовать.

Предполагая, что я реализую классическую функцию ForEach, которая принимает срез или карту в качестве аргумента. Чтобы проверить, прошел ли итерабельность, я мог бы сделать:

func ForEach(iterable interface{}, f interface{}) {
    if isNotIterable(iterable) {
        panic("Should pass in a slice or map!")
    }
}

или

func ForEach(iterable interface{}, f interface{}) error {
    if isNotIterable(iterable) {
        return fmt.Errorf("Should pass in a slice or map!")
    }
}

Я видел некоторые обсуждения, в которых говорилось, что panic() следует избегать, но люди также говорят, что если программа не может восстановиться после ошибки, вы должны panic().

Какой я должен использовать? И какой главный принцип для выбора правильного?

Ответ 1

Из Дейв Чейни:

panics всегда являются фатальными для вашей программы. При панировании вы никогда не предполагаете что ваш вызывающий может решить проблему. Следовательно, panic используется только в исключительные обстоятельства, когда это невозможно для вашего код или кто-либо, интегрирующий ваш код для продолжения.

Вы должны предположить, что паника будет немедленно фатальной, для всей программы или, по крайней мере, для текущей версии goroutine. Спросите себя, "когда это произойдет, если приложение немедленно рухнет?" Если да, используйте панику; в противном случае используйте ошибку.

Ответ 2

Используйте panic.

Потому что ваш вариант использования - поймать, что ваш API используется не так, как надо. Это никогда не должно происходить во время выполнения, если программа правильно вызывает ваш API.

Фактически, любая программа, вызывающая ваш API с правильными аргументами, будет вести себя так же, если тест удален. Тест может завершиться неудачно на ранней стадии с сообщением об ошибке, полезным для программиста, который допустил ошибку. В идеале паника может быть достигнута один раз во время разработки при запуске testsuite, и программист исправит вызов даже перед фиксацией плохого кода, и это неправильное использование никогда не достигнет производства.

См. также этот ответ на вопрос. Является ли проверка параметров функции с помощью ошибок хорошим примером в Go?.

Ответ 3

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

Ответ 4

Если какое-либо обязательное требование не предоставляется или нет при запуске службы (например, подключение к базе данных, какая-то необходимая конфигурация службы), вы должны использовать панику.

Должна быть ошибка возврата для любой реакции пользователя или ошибки на стороне сервера.

Ответ 5

Задайте себе эти вопросы:

  • Ожидаете ли вы возникновения исключительной ситуации, независимо от того, насколько хорошо вы закодируете свое приложение? Считаете ли вы, что это должно быть полезно, чтобы пользователь знал о таком состоянии как часть обычного использования вашего приложения? Обработайте это как ошибку, потому что это касается приложения как работающего нормально.
  • Не должна ли эта исключительная ситуация возникать, если вы кодируете надлежащим образом (и в некоторой степени защитно)? (пример: деление на ноль или доступ к элементу массива за пределами границ) Является ли ваше приложение совершенно невежественным в связи с этой ошибкой? Паника.
  • У вас есть API и вы хотите, чтобы пользователи использовали его надлежащим образом? Паника. Ваш API редко восстанавливается, если используется неправильно.

Ответ 6

Не используйте панику для нормальной обработки ошибок. Используйте ошибку и несколько возвращаемых значений. См. https://golang.org/doc/effective_go.html#errors.