Вопрос с собеседования · Go

Почему интерфейс с nil-указателем внутри не равен nil?

MiddleМетоды и интерфейсы
Ещё спрашивают так:
  • Почему функция вернула error, который не nil, хотя внутри nil?
Коротко

Интерфейсное значение — пара (тип, значение). Оно равно nil, только когда обе части nil. Если положить в интерфейс nil-указатель конкретного типа, тип уже заполнен — интерфейс не nil, и err != nil срабатывает.

  • Классика: функция возвращает *MyError, равный nil, через тип error
  • Правило: возвращать именно nil, а не типизированный nil-указатель
  • Посмотреть пару — fmt.Printf("%T %v", err, err)

А ещё Метод на nil-указателе можно вызвать — если он не обращается к полям

Подробно

Почему так. Сравнение интерфейса с nil проверяет, что в нём нет ни типа, ни значения. Присваивание var err error = (*MyErr)(nil) записывает тип *MyErr — интерфейс «знает», что внутри указатель на MyErr, просто этот указатель пустой.

Где встречается: функции, возвращающие конкретный тип ошибки через промежуточную переменную; фабрики, возвращающие интерфейс и nil-указатель реализации; поля-интерфейсы, заполненные из nil-указателей.

Как избегать: возвращать nil литералом; объявлять результат функции интерфейсом error с самого начала; линтеры (nilness, staticcheck) ловят часть случаев.

Пример

type MyErr struct{}
func (*MyErr) Error() string { return "ошибка" }

func check(ok bool) error {
    var e *MyErr          // nil-указатель
    if !ok { e = &MyErr{} }
    return e              // интерфейс (тип *MyErr, значение nil) — не nil!
}

fmt.Println(check(true) == nil)   // false

// правильно
func check2(ok bool) error {
    if !ok { return &MyErr{} }
    return nil
}

Что хотят услышать

  • Устройство интерфейса как пары.
  • Пример с error.
  • Как избежать.

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

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Интерфейс — пара (тип, значение); nil, только если обе nil
  • ✗Интерфейс с nil-указателем внутри всегда равен nil, просто == сравнивает адреса
  • ✗Это ошибка компилятора
  • ✗Возвращать типизированный nil-указатель через error — идиоматично

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования