Menu
Coddy logo textTech

Распаковка с помощью `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 корректно работает с обернутыми ошибками и следует по цепочке ошибок для поиска совпадений. Это делает вашу обработку ошибок надежной и стабильной, даже когда ошибки проходят через несколько уровней вашего приложения.

quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

challenge icon

Задание

Легко

Создайте систему мониторинга подключения к базе данных, которая использует errors.Is для идентификации конкретных ошибок подключения в цепочках обернутых ошибок. Эта задача демонстрирует, как использовать errors.Is для обнаружения сигнальных ошибок (sentinel errors), даже если они были обернуты дополнительным контекстом на нескольких уровнях приложения.

Вы получите два входных значения:

  • Строку, содержащую детали операции с базой данных в формате "database_name,operation,error_type" (например, "users_db,connect,connection_timeout")
  • Строку, содержащую контекст приложения в формате "service_name,retry_count" (например, "AuthService,3")

Ваша задача:

  1. Определить три сигнальные ошибки с помощью errors.New():
    • ErrConnectionTimeout с сообщением "connection timeout"
    • ErrConnectionRefused с сообщением "connection refused"
    • ErrDatabaseNotFound с сообщением "database not found"
  2. Разобрать первый входной параметр, разделив его по запятым, чтобы получить имя базы данных, операцию и тип ошибки.
  3. Разобрать второй входной параметр, разделив его по запятым, чтобы получить имя сервиса и количество повторных попыток.
  4. Создать исходную ошибку на основе типа ошибки:
    • Если тип ошибки "connection_timeout": используйте ErrConnectionTimeout
    • Если тип ошибки "connection_refused": используйте ErrConnectionRefused
    • Если тип ошибки "database_not_found": используйте ErrDatabaseNotFound
    • Для любого другого типа ошибки: используйте errors.New("unknown database error")
  5. Создать обернутую ошибку уровня базы данных, используя fmt.Errorf с %w: "failed to [operation] database [database_name]: %w"
  6. Создать обернутую ошибку уровня сервиса: "[service_name] database operation failed after [retry_count] retries: %w"
  7. Использовать errors.Is, чтобы проверить, соответствует ли итоговая обернутая ошибка каждой сигнальной ошибке, и вывести результаты:
    • "Checking for connection timeout: [true/false]"
    • "Checking for connection refused: [true/false]"
    • "Checking for database not found: [true/false]"
  8. Отобразить цепочку ошибок:
    • "Error Chain:"
    • "Original: [original_error_message]"
    • "Database level: [database_level_error_message]"
    • "Service level: [service_level_error_message]"
  9. Отобразить анализ ошибки:
    • "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. Выведите результаты и цепочку ошибок
	
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Логика и управление потоком