Что мне лучше использовать: отложить-панику-восстановить или проверить, если err != nil {//сделать что-то} в golang?

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

_,insert_err := stmt.Run(query)
if insert_err != nil{
    mylogs.Error(insert_err.Error())
    return db_updation_status
}

Для этого я определяю db_updation_status в начале как «false» и не делаю его «true», пока все в программе не пойдет правильно. Я делал это в каждой функции после каждой операции, которая, как мне кажется, могла пойти не так.

Как вы думаете, есть ли лучший способ сделать это с помощью defer-panic-recover? Я прочитал об этом здесь http://golang.org/doc/articles/defer_panic_recover.html, но не могу понять, как их использовать. Предлагают ли эти конструкции что-то похожее на обработку исключений? Мне лучше без этих конструкций? Я был бы очень признателен, если бы кто-нибудь объяснил мне это простым языком и/или предоставил вариант использования этих конструкций и сравнил их с типом обработки ошибок, который я использовал выше.


person pymd    schedule 07.06.2013    source источник


Ответы (3)


Более удобно возвращать значения error — они могут нести больше информации (преимущество для клиента/пользователя). ), чем двухзначный bool.

Что касается паники/восстановления: есть сценарии, где их использование вполне разумно. Например, в написанном от руки синтаксическом анализаторе с рекурсивным спуском вполне достаточно PITA, чтобы "пузырить" условие ошибки на всех уровнях вызова. В этом примере приветствуется упрощение, если на самом верхнем уровне (API) есть отложенное восстановление, и можно сообщить о любой ошибке на любом уровне вызова, используя, например

panic(fmt.Errorf("Cannot %v in %v", foo, bar))
person zzzz    schedule 07.06.2013
comment
Дополнительное замечание по этикету для пакетов: пакет никогда не должен «пропускать» панику, но всегда должен возвращать ошибку при вызове функции. Как вы будете обращаться с вещами внутри пакета — это ваш выбор, и предложение jnml — хороший способ сделать это. - person jimt; 07.06.2013
comment
Вам следует ознакомиться с выступлением Роба Пайка о написании лексеров на Go — его решение не вообще не использовать panic/defer, это очень элегантно и читабельно. - person Silas Snider; 08.06.2013
comment
@silas: парсер рекурсивного спуска не является лексером. Совершенно другая проблема. - person zzzz; 08.06.2013

Если операция может завершиться неудачно и вернуть ошибку, то немедленная проверка этой ошибки и ее правильная обработка — это идиоматично, просто и приятно проверять, правильно ли что-то обрабатывается.

Не используйте отсрочку/восстановление для таких вещей: необходимые действия по очистке трудно закодировать, особенно если вещи вложены друг в друга.

person Volker    schedule 07.06.2013
comment
большое спасибо за твою помощь! Сначала я так и сделал, но потом узнал про отсрочку/восстановление и запутался. - person pymd; 07.06.2013

Обычный способ сообщить вызывающей стороне об ошибке — вернуть ошибку в качестве дополнительного возвращаемого значения. Канонический метод Read является хорошо известным примером; он возвращает количество байтов и ошибку. Но что, если ошибка неисправима? Иногда программа просто не может продолжать работу. Для этой цели существует встроенная функция panic, которая фактически создает ошибку времени выполнения, которая останавливает программу (но см. следующий раздел). Функция принимает один аргумент произвольного типа — часто строку — для вывода на экран после завершения программы. Это также способ указать, что произошло что-то невозможное, например, выход из бесконечного цикла.

http://golang.org/doc/efficient_go.html#errors

person XIO    schedule 08.06.2013