Раньше мы разбирали, что обычный интерфейс это структура из двух указателей, на таблицу типа и на данные. Пустой интерфейс, он же
any, устроен похоже, но проще, и об этом стоит знать отдельно.Непустой интерфейс в рантайме это
iface. Внутри у него itab, где лежат тип интерфейса, конкретный тип, хеш и таблица методов. У пустого интерфейса методов нет, значит и таблица методов ему не нужна. Поэтому any представлен другой, более лёгкой структурой, eface.
type eface struct {
_type *_type
data unsafe.Pointer
}
Здесь
_type это указатель на описание конкретного типа, а data это указатель на само значение. Никакого itab и списка методов, потому что вызывать через any всё равно нечего. Из-за этого приведение типа и type switch по any сводятся к сравнению указателя на тип, без похода в таблицу методов.Из устройства следует известный подвох. Интерфейс равен
nil, только когда оба поля пустые, и тип, и данные. Стоит завернуть в интерфейс нетипизированный `nil`-указатель, и получится интерфейс, у которого тип уже не пустой.
var p *MyError = nil
var err error = p
fmt.Println(err == nil) // false
Тип внутри
err теперь *MyError, поэтому сравнение с nil даёт false, хотя указатель внутри нулевой. Отсюда практичное правило. Возвращайте из функций именно nil литералом, а не заранее объявленную типизированную переменную, если хотите, чтобы вызывающий код честно увидел nil.📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep

