Распаковка с помощью `errors.Is`
Часть раздела Логика и управление потоком путешествия по GO на Coddy — урок 40 из 68.
При работе с обернутыми ошибками вам нужен способ проверить, существует ли конкретная ошибка где-либо в цепочке ошибок. Функция errors.Is предоставляет именно такую возможность, позволяя идентифицировать сигнальные ошибки (sentinel errors), даже если они были обернуты несколько раз.
Функция errors.Is принимает два параметра: ошибку, которую вы хотите проверить, и целевую ошибку, которую вы ищете. Она возвращает true, если целевая ошибка найдена где-либо в цепочке ошибок:
var ErrNotFound = errors.New("not found")
wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)
if errors.Is(wrappedErr, ErrNotFound) {
fmt.Println("This is a not found error")
}Это современный, рекомендуемый способ проверки конкретных ошибок в Go. В отличие от сравнения строк или прямой проверки на равенство, errors.Is корректно работает с обернутыми ошибками и следует по цепочке ошибок для поиска совпадений. Это делает вашу обработку ошибок надежной и стабильной, даже когда ошибки проходят через несколько уровней вашего приложения.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Задание
ЛегкоСоздайте систему мониторинга подключения к базе данных, которая использует errors.Is для идентификации конкретных ошибок подключения в цепочках обернутых ошибок. Эта задача демонстрирует, как использовать errors.Is для обнаружения сигнальных ошибок (sentinel errors), даже если они были обернуты дополнительным контекстом на нескольких уровнях приложения.
Вы получите два входных значения:
- Строку, содержащую детали операции с базой данных в формате
"database_name,operation,error_type"(например,"users_db,connect,connection_timeout") - Строку, содержащую контекст приложения в формате
"service_name,retry_count"(например,"AuthService,3")
Ваша задача:
- Определить три сигнальные ошибки с помощью
errors.New():ErrConnectionTimeoutс сообщением"connection timeout"ErrConnectionRefusedс сообщением"connection refused"ErrDatabaseNotFoundс сообщением"database not found"
- Разобрать первый входной параметр, разделив его по запятым, чтобы получить имя базы данных, операцию и тип ошибки.
- Разобрать второй входной параметр, разделив его по запятым, чтобы получить имя сервиса и количество повторных попыток.
- Создать исходную ошибку на основе типа ошибки:
- Если тип ошибки
"connection_timeout": используйтеErrConnectionTimeout - Если тип ошибки
"connection_refused": используйтеErrConnectionRefused - Если тип ошибки
"database_not_found": используйтеErrDatabaseNotFound - Для любого другого типа ошибки: используйте
errors.New("unknown database error")
- Если тип ошибки
- Создать обернутую ошибку уровня базы данных, используя
fmt.Errorfс%w:"failed to [operation] database [database_name]: %w" - Создать обернутую ошибку уровня сервиса:
"[service_name] database operation failed after [retry_count] retries: %w" - Использовать
errors.Is, чтобы проверить, соответствует ли итоговая обернутая ошибка каждой сигнальной ошибке, и вывести результаты:"Checking for connection timeout: [true/false]""Checking for connection refused: [true/false]""Checking for database not found: [true/false]"
- Отобразить цепочку ошибок:
"Error Chain:""Original: [original_error_message]""Database level: [database_level_error_message]""Service level: [service_level_error_message]"
- Отобразить анализ ошибки:
"Error Analysis:""Database: [database_name]""Operation: [operation]""Service: [service_name]""Retries: [retry_count]""Error type detected: [detected_error_type]", где detected_error_type — это одно из значений "Connection Timeout", "Connection Refused", "Database Not Found" или "Unknown Error"
Используйте пакет strings для разделения входных строк по запятым, пакет errors для сигнальных ошибок и errors.Is, а также пакет fmt для оборачивания ошибок. Эта задача демонстрирует, как errors.Is обеспечивает надежную идентификацию ошибок, которая корректно работает с обернутыми ошибками, что делает ее необходимой для надежной обработки ошибок в сложных приложениях.
Шпаргалка
Функция errors.Is проверяет, существует ли конкретная ошибка в цепочке ошибок, даже если она была обернута несколько раз:
var ErrNotFound = errors.New("not found")
wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)
if errors.Is(wrappedErr, ErrNotFound) {
fmt.Println("This is a not found error")
}errors.Is принимает два параметра: проверяемую ошибку и целевую ошибку, которую нужно найти. Она возвращает true, если целевая ошибка найдена в любом месте цепочки ошибок.
Это современный, рекомендуемый способ проверки конкретных ошибок в Go, так как он корректно работает с обернутыми ошибками, в отличие от сравнения строк или прямой проверки на равенство.
Попробуйте сами
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
// Чтение входных данных
var dbOperation string
var appContext string
fmt.Scanln(&dbOperation)
fmt.Scanln(&appContext)
// Парсинг входных данных
dbParts := strings.Split(dbOperation, ",")
databaseName := dbParts[0]
operation := dbParts[1]
errorType := dbParts[2]
contextParts := strings.Split(appContext, ",")
serviceName := contextParts[0]
retryCount := contextParts[1]
// TODO: Напишите свой код ниже
// 1. Определите три ошибки-метки (sentinel errors), используя errors.New()
// 2. Создайте исходную ошибку на основе типа ошибки
// 3. Создайте обернутую ошибку уровня базы данных, используя fmt.Errorf с %w
// 4. Создайте обернутую ошибку уровня сервиса
// 5. Используйте errors.Is для проверки каждой ошибки-метки
// 6. Выведите результаты и цепочку ошибок
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Логика и управление потоком
1Продвинутое управление потоком выполнения
Switch с использованием `fallthrough`Выход из вложенных цикловПродолжение конкретного циклаОператор `goto`Итоги: Продвинутое управление циклами4Проект: Простой список задач
Настройка проектаДобавление задачи7Углубленная обработка ошибок
Пользовательские типы ошибокОбертывание ошибок с помощью `%w`Распаковка с помощью `errors.Is`Распаковка с помощью `errors.As`Понимание `panic`Использование `recover`Итоги: Безопасное деление2Структуры и методы
Определение методов для структурПолучатели по значениюПолучатели по указателюВыбор типа получателяМетоды против функцийИтоги: поведение структур5Карты: подробный разбор
Карты структурУказатели как значения картПроверка карт на nilСравнение картИтоги: счетчик частоты слов3Интерфейсы (Основы)
Что такое интерфейс?Определение интерфейсаРеализация интерфейсаИспользование интерфейсных типовПустой интерфейсУтверждение типаПереключатель типовИтоги: Фигуры и поведение