Go: почему err == nil может вернуть false, хотя ошибки нет 🛑

Представим обычную функцию, которая возвращает ошибку:

func doSomething() error { var err *MyError = nil return err }

На первый взгляд всё нормально: err равен nil, значит, ошибки нет.

Но проверим:

func main() { err := doSomething() fmt.Println(err == nil) // false }

Неожиданно? Причина в том, как го работает с интерфейсами. Что здесь происходит?

type MyError struct{} func (e *MyError) Error() string { return "something went wrong" }

Тип *MyError реализует интерфейс error.

Когда функция возвращает типизированный nil-указатель как error, интерфейс получает динамический тип *MyError и значение nil.

Условно это выглядит так:

error ├── dynamic type: *MyError └── dynamic value: nil

Сам интерфейс уже не равен nil, потому что в нём сохранена информация о типе. Как правильно?

Если ошибки нет, возвращаем обычный nil: func doSomething() error { // Выполняем работу return nil }

Или, если ошибка возникает при определённых условиях:

func doSomething() error { var err *MyError if someCondition { err = &MyError{} } if err != nil { return err } return nil }

Вывод: если функция возвращает интерфейс error, не стоит без необходимости возвращать из неё типизированный nil-указатель.

Это небольшой нюанс, который легко пропустить при работе с собственными типами ошибок и интерфейсами.