💬 Почему значение ошибки типа nil не равно nil?
Под капотом интерфейсы реализованы как два элемента: тип
Значение
Значение интерфейса является
Эта ситуация может быть запутанной и возникает, когда
Если всё идет хорошо, функция возвращает
Хорошей практикой для функций, возвращающих ошибки, является использование типа
Под капотом интерфейсы реализованы как два элемента: тип
T
и значение V
. V
— это конкретное значение, такое как int, структура или указатель. Например, если мы сохраняем значение int 3 в интерфейсе, полученное значение интерфейса схематически будет (T=int
, V=3
). Значение
V
также известно как динамическое значение интерфейса, поскольку одна и та же переменная интерфейса может хранить разные значения V
(и соответствующие типы T
) во время выполнения программы.Значение интерфейса является
nil
только если и V
, и T
не установлены. В частности, nil
интерфейс всегда будет содержать nil
тип. Если мы сохраняем nil
указатель типа *int
внутри значения интерфейса, внутренний тип будет *int
независимо от значения указателя: (T=*int
, V=nil
). Таким образом, значение интерфейса будет не nil
, даже когда значение указателя V
внутри является nil
.Эта ситуация может быть запутанной и возникает, когда
nil
значение сохраняется внутри значения интерфейса, например, в возвращаемом значении ошибки:func returnsError() error {
var p *MyError = nil
if bad() {
p = ErrBad
}
return p // Всегда вернет не nil ошибку.
}
Если всё идет хорошо, функция возвращает
nil
p
, так что возвращаемое значение — это значение интерфейса ошибки, содержащее (T=*MyError
, V=nil
). Это означает, что если вызывающий сравнивает возвращенную ошибку с nil
, он всегда будет видеть, как будто произошла ошибка, даже если ничего плохого не случилось. Чтобы вернуть правильную nil
ошибку вызывающему, функция должна явно вернуть nil
:func returnsError() error {
if bad() {
return ErrBad
}
return nil
}
Хорошей практикой для функций, возвращающих ошибки, является использование типа
error
в их сигнатуре (как сделано выше), а не конкретного типа, например *MyError
, чтобы помочь гарантировать, что ошибка создается правильно.