У функции с именованным результатом есть deferred-восстановление после panic: какое значение она вернёт, если обработчик изменит этот результат?
Если deferred-обработчик вызывает recover и изменяет именованный результат, функция завершится с изменённым значением. Выполнение с места возникновения panic не продолжится.
Если обработчик перехватит панику, но не изменит результат, функция вернёт текущее значение именованного результата, часто его нулевое значение. Поэтому восстановление без явного формирования результата может скрыть ошибку, например вернуть nil вместо ожидаемого error.
В Go обычные ожидаемые сбои принято явно возвращать через error, а panic/recover предназначены для исключительных ситуаций и защиты границ приложения. Такой подход позволяет не превращать каждую внутреннюю ошибку в исключение, но при этом централизованно обработать нарушение инварианта или неожиданную ошибку в обработчике запроса.
Именованные результаты существуют как часть сигнатуры функции и доступны deferred-функциям до фактического возврата. Это даёт обработчику возможность преобразовать перехваченную панику в обычный результат функции.
Функция может выполнить часть работы, затем вызвать panic. Deferred-функции всё равно запускаются во время раскрутки стека, и одна из них может вызвать recover.
Неверное предположение состоит в том, что после recover функция продолжит выполнение с точки сбоя. На самом деле она завершает работу; если результат не подготовлен явно, наружу может уйти нулевое или частично сформированное значение.
Именованный результат является переменной, связанной с возвращаемым значением функции. При обычном return его значение передаётся вызывающему коду, а deferred-функции выполняются перед фактическим возвратом и могут это значение изменить.
Если recover вызван непосредственно из deferred-функции, паника прекращается. Тело функции не возобновляется, а управление переходит к завершению этой функции с текущими значениями результатов.
Здесь run вернёт созданную обработчиком ошибку. Строка после panic не выполняется, но deferred-функция успевает присвоить значение переменной err.
При проектировании важно отличать восстановление от подавления проблемы. На границе HTTP-сервера обычно безопасно перехватить панику, записать стек вызовов в журнал и вернуть клиенту контролируемый ответ, но не следует бездумно превращать любую панику в успешный результат.
Если результат функции не именованный, deferred-функция не может изменить конкретную переменную результата по имени. После перехвата паники функция всё равно завершится с нулевыми значениями своих результатов, если они не были сохранены другим способом.
Внутренний обработчик запроса вызывает код стороннего расширения. Расширение может вызвать panic, а HTTP-сервер должен сохранить доступность процесса и вернуть статус внутренней ошибки.
Вариант без восстановления прост, но одна паника завершит горутину обработки, а в зависимости от места возникновения может нарушить работу всего процесса. Вариант с восстановлением и возвратом nil удобен технически, но скрывает сбой и может привести к ошибочному успешному ответу.
Выбранный вариант — deferred middleware на границе запроса: он вызывает recover, записывает значение паники и стек, устанавливает внутреннюю ошибку или напрямую формирует ответ с ошибкой. Внутренние функции при этом продолжают использовать обычные error, а panic остаётся механизмом аварийного выхода для действительно исключительных случаев.
Результат — процесс не падает из-за единичного сбоя расширения, клиент получает предсказуемый ответ, а команда сохраняет диагностическую информацию. При этом восстановление не маскирует проблему: паника регистрируется как ошибка программного компонента.
Функция завершится с текущим значением результата. Если до паники именованный error имел значение nil, вызывающий код может получить nil и ошибочно считать операцию успешной. Поэтому обработчик должен явно сформировать корректный результат либо повторно вызвать panic, если восстановление на данном уровне не предусмотрено.
Нет. recover прекращает раскрутку стека, но не откатывает управление к месту сбоя и не возобновляет тело функции. Функция, в которой произошла паника, заканчивает выполнение после deferred-функций; для продолжения операции нужно заранее разделить её на отдельные этапы и повторно вызвать нужный этап явно.
Паника может означать нарушение инварианта, повреждённое состояние или ошибку программирования, а не штатную ошибку ввода-вывода. Если просто записать её в error без журналирования, метрик и проверки состояния, система продолжит работу с потенциально некорректными данными. Поэтому восстановление обычно ограничивают внешней границей, фиксируют диагностический контекст и отдельно решают, безопасно ли продолжать обработку.