Распаковка с помощью `errors.As`
Часть раздела Логика и управление потоком путешествия по GO на Coddy — урок 41 из 68.
В то время как errors.Is помогает идентифицировать конкретные значения ошибок в цепочке, иногда вам нужно получить доступ к фактическим полям и данным пользовательского типа ошибки. Функция errors.As предоставляет эту возможность, находя первую ошибку в цепочке, которая соответствует определенному типу, и извлекая ее для проверки.
Функция errors.As принимает два параметра: проверяемую ошибку и указатель на переменную целевого типа ошибки. Если она находит соответствующий тип ошибки в цепочке, она присваивает вашей переменной значение этой ошибки и возвращает true:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}Это особенно эффективно при работе с пользовательскими типами ошибок, которые содержат дополнительный контекст. В отличие от errors.Is, которая проверяет только на равенство, errors.As извлекает фактический экземпляр ошибки, позволяя вам обращаться к её полям и методам. Это делает обработку ошибок более сложной и информативной в комплексных приложениях.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Задание
ЛегкоСоздайте систему обработки ошибок API, которая использует errors.As для извлечения и анализа пользовательских типов ошибок из цепочек обернутых ошибок. Эта задача демонстрирует, как использовать errors.As для доступа к полям и данным конкретных пользовательских типов ошибок, даже если они были обернуты дополнительным контекстом.
Вы получите два входных значения:
- Строку, содержащую детали запроса API в формате
"endpoint,method,error_code,error_field"(например,"/users,POST,400,email") - Строку, содержащую системный контекст в формате
"service_name,request_id"(например,"UserAPI,req_12345")
Ваша задача:
- Создать пользовательский тип ошибки — структуру
APIErrorс тремя полями:Code(int) — код статуса HTTPField(string) — поле, вызвавшее ошибкуMessage(string) — описание ошибки
- Реализовать метод
Error() stringдляAPIError, который возвращает:"API error [code]: [message] (field: [field])" - Разобрать первый входной параметр, разделив его по запятым, чтобы получить endpoint, method, error code и error field
- Разобрать второй входной параметр, разделив его по запятым, чтобы получить service name и request ID
- Преобразовать строку кода ошибки в целое число
- Создать экземпляр
APIErrorна основе кода ошибки:- Если код 400: сообщение
"invalid request data" - Если код 401: сообщение
"authentication required" - Если код 404: сообщение
"resource not found" - Если код 500: сообщение
"internal server error" - Для любого другого кода: сообщение
"unknown error"
- Если код 400: сообщение
- Создать обернутую ошибку уровня эндпоинта, используя
fmt.Errorfс%w:"[method] [endpoint] failed: %w" - Создать обернутую ошибку уровня сервиса:
"[service_name] request [request_id] failed: %w" - Использовать
errors.Asдля извлеченияAPIErrorиз цепочки обернутых ошибок и вывести результат извлечения:- Если извлечение прошло успешно:
"API error extracted successfully" - Если извлечение не удалось:
"Failed to extract API error"
- Если извлечение прошло успешно:
- Если извлечение прошло успешно, вывести детали извлеченной ошибки:
"Extracted Error Details:""Code: [code]""Field: [field]""Message: [message]""Full error: [full_error_message_from_Error_method]"
- Вывести полную цепочку ошибок:
"Error Chain:""Original: [original_api_error_message]""Endpoint level: [endpoint_level_error_message]""Service level: [service_level_error_message]"
- Вывести финальный анализ:
"Error Analysis:""Service: [service_name]""Request ID: [request_id]""Endpoint: [method] [endpoint]""HTTP Status: [code]""Problem Field: [field]""Error Category: [error_category]", где error_category — это "Client Error" для кодов 400-499, "Server Error" для кодов 500-599 или "Unknown" для других кодов
Используйте пакет strings для разделения входных строк по запятым, пакет strconv для преобразования строки кода ошибки в целое число, пакет errors для errors.As и пакет fmt для оборачивания ошибок. Это задание демонстрирует, как errors.As позволяет получить доступ к конкретным полям и методам пользовательских типов ошибок внутри цепочек обернутых ошибок, обеспечивая сложную обработку и анализ ошибок.
Шпаргалка
Функция errors.As извлекает конкретные типы ошибок из цепочек ошибок, предоставляя доступ к пользовательским полям и методам ошибки.
errors.As принимает два параметра: проверяемую ошибку и указатель на переменную целевого типа ошибки:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}В отличие от errors.Is, которая только проверяет на равенство, errors.As извлекает сам экземпляр ошибки, позволяя обращаться к её полям и методам для более сложной обработки ошибок.
Попробуйте сами
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Считать входные данные
var apiDetails string
var systemContext string
fmt.Scanln(&apiDetails)
fmt.Scanln(&systemContext)
// Разобрать входные данные
apiParts := strings.Split(apiDetails, ",")
endpoint := apiParts[0]
method := apiParts[1]
errorCodeStr := apiParts[2]
errorField := apiParts[3]
contextParts := strings.Split(systemContext, ",")
serviceName := contextParts[0]
requestID := contextParts[1]
// Преобразовать код ошибки в целое число
errorCode, _ := strconv.Atoi(errorCodeStr)
// TODO: Напишите свой код ниже
// 1. Создайте структуру APIError с полями Code, Field, Message
// 2. Реализуйте метод Error() для APIError
// 3. Создайте экземпляр APIError на основе кода ошибки
// 4. Создайте обернутые ошибки (уровня эндпоинта и уровня сервиса)
// 5. Используйте errors.As для извлечения APIError из цепочки обернутых ошибок
// 6. Выведите результат извлечения и детали ошибки
// 7. Выведите цепочку ошибок и финальный анализ
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Логика и управление потоком
1Продвинутое управление потоком выполнения
Switch с использованием `fallthrough`Выход из вложенных цикловПродолжение конкретного циклаОператор `goto`Итоги: Продвинутое управление циклами4Проект: Простой список задач
Настройка проектаДобавление задачи7Углубленная обработка ошибок
Пользовательские типы ошибокОбертывание ошибок с помощью `%w`Распаковка с помощью `errors.Is`Распаковка с помощью `errors.As`Понимание `panic`Использование `recover`Итоги: Безопасное деление2Структуры и методы
Определение методов для структурПолучатели по значениюПолучатели по указателюВыбор типа получателяМетоды против функцийИтоги: поведение структур5Карты: подробный разбор
Карты структурУказатели как значения картПроверка карт на nilСравнение картИтоги: счетчик частоты слов3Интерфейсы (Основы)
Что такое интерфейс?Определение интерфейсаРеализация интерфейсаИспользование интерфейсных типовПустой интерфейсУтверждение типаПереключатель типовИтоги: Фигуры и поведение