← Назад ко всем вопросам

Что такое wrapped errors и зачем нужны fmt.Errorf("%w"), errors.Is, errors.As

1️⃣ Как кратко ответить

Wrapped errors в Go позволяют оборачивать ошибки для сохранения контекста и цепочки ошибок. Функция fmt.Errorf("%w", err) используется для оборачивания ошибок, errors.Is — для проверки, является ли ошибка конкретной ошибкой в цепочке, а errors.As — для извлечения конкретного типа ошибки из цепочки.

2️⃣ Подробное объяснение темы

В Go обработка ошибок является важной частью программирования. Wrapped errors (обернутые ошибки) позволяют добавлять контекст к ошибкам, сохраняя при этом оригинальную ошибку. Это полезно для отладки и понимания того, что именно пошло не так в программе.

Зачем нужны wrapped errors?

Когда в программе возникает ошибка, важно не только знать, что она произошла, но и понимать, в каком контексте это случилось. Например, если функция не смогла открыть файл, полезно знать, какой именно файл и почему. Обернутые ошибки позволяют добавлять такую информацию, сохраняя при этом оригинальную ошибку.

Как работают wrapped errors?

В Go для оборачивания ошибок используется функция fmt.Errorf с форматом %w. Это позволяет создать новую ошибку, которая содержит оригинальную ошибку и дополнительный контекст.

package main
​
import (
	"errors"
	"fmt"
	"os"
)
​
func main() {
	_, err := os.Open("nonexistentfile.txt")
	if err != nil {
		// Оборачиваем ошибку, добавляя контекст
		wrappedErr := fmt.Errorf("failed to open file: %w", err)
		fmt.Println(wrappedErr)
	}
}
  • os.Open("nonexistentfile.txt"): Пытается открыть несуществующий файл, возвращая ошибку.
  • fmt.Errorf("failed to open file: %w", err): Создает новую ошибку, оборачивая оригинальную ошибку err и добавляя контекст "failed to open file".

Использование errors.Is

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

package main
​
import (
	"errors"
	"fmt"
	"os"
)
​
func main() {
	_, err := os.Open("nonexistentfile.txt")
	if err != nil {
		wrappedErr := fmt.Errorf("failed to open file: %w", err)
		if errors.Is(wrappedErr, os.ErrNotExist) {
			fmt.Println("File does not exist")
		}
	}
}
  • errors.Is(wrappedErr, os.ErrNotExist): Проверяет, является ли wrappedErr ошибкой os.ErrNotExist, даже если она обернута.

Использование errors.As

Функция errors.As позволяет извлечь конкретный тип ошибки из цепочки обернутых ошибок. Это полезно, когда нужно работать с конкретным типом ошибки, например, для получения дополнительных данных.

package main
​
import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
)
​
func main() {
	_, err := os.Open("nonexistentfile.txt")
	if err != nil {
		wrappedErr := fmt.Errorf("failed to open file: %w", err)
		var pathError *os.PathError
		if errors.As(wrappedErr, &pathError) {
			fmt.Printf("Path error: %v\n", pathError.Path)
		}
	}
}
  • var pathError *os.PathError: Объявляет переменную для хранения ошибки типа *os.PathError.
  • errors.As(wrappedErr, &pathError): Извлекает ошибку типа *os.PathError из wrappedErr, если она присутствует.

Заключение

Wrapped errors и функции fmt.Errorf("%w"), errors.Is, errors.As предоставляют мощные инструменты для работы с ошибками в Go, позволяя добавлять контекст, проверять и извлекать ошибки из цепочки. Это делает обработку ошибок более гибкой и информативной.

Тема: Ошибки, тестирование
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки