Интерфейсы

16 вопросов

Интерфейсы в Go реализуются неявно (duck typing). Пустой интерфейс interface{} (any), type assertion, type switch и тонкости с nil-интерфейсами - частые темы собеседований.

1 Что такое интерфейс в Go? 🟢 Лёгкий
Ответ: B) Набор методов, которые тип должен реализовать

Интерфейс определяет контракт - набор методов. Любой тип, который имеет все эти методы, автоматически реализует интерфейс. Нет абстрактных классов - интерфейсы полностью заменяют их в Go.

Подробнее →
2 Нужно ли явно указывать, что тип реализует интерфейс? 🟢 Лёгкий
Ответ: B) Нет, реализация неявная

Go использует структурную типизацию (duck typing): если тип имеет все методы интерфейса, он его реализует. Не нужно писать implements. Тип может реализовать интерфейс из другого пакета, не зная о нём.

Подробнее →
3 Что такое пустой интерфейс interface{}? 🟢 Лёгкий
Ответ: A) Интерфейс без методов, принимает любой тип

interface{} (или any с Go 1.18) не содержит методов, поэтому любой тип его реализует. Используется для хранения значений произвольного типа. Для извлечения конкретного типа нужен type assertion.

Подробнее →
4 Что произойдёт при неудачном type assertion без ok? 🟢 Лёгкий
Ответ: B) panic

Однозначный type assertion x.(int) вызывает panic, если тип не совпадает. Безопасная форма v, ok := x.(int) возвращает ok = false и zero value, без паники.

Подробнее →
5 Что такое any в Go 1.18+? 🟢 Лёгкий
Ответ: B) Алиас для interface{}

any - встроенный алиас для interface{}, введённый в Go 1.18 для краткости. func Print(v any) читается лучше, чем func Print(v interface{}). Функционально они идентичны.

Подробнее →
6 Сколько методов определено в интерфейсе io.Reader? 🟢 Лёгкий
Ответ: A) 1

io.Reader содержит только один метод: Read(p []byte) (n int, err error). Минимальные интерфейсы с одним методом - философия Go. io.Writer тоже содержит только Write. Маленькие интерфейсы проще реализовать и комбинировать.

Подробнее →
7 Что делает type assertion x.(int)? 🟡 Средний
Ответ: B) Извлекает значение типа int из интерфейса

Type assertion проверяет, что интерфейсная переменная содержит значение конкретного типа, и извлекает его. v := x.(int) - если x не содержит int, будет panic. Безопасная форма: v, ok := x.(int).

Подробнее →
8 Что такое type switch? 🟡 Средний
Ответ: B) switch по типу интерфейсной переменной

Type switch позволяет выполнять разный код в зависимости от конкретного типа значения в интерфейсе: switch v := x.(type) { case int: ... case string: ... }. Удобнее цепочки type assertions.

Подробнее →
9 Нужно ли передавать интерфейс по указателю (*MyInterface)? 🟡 Средний
Ответ: B) Почти никогда - интерфейс уже содержит указатели внутри

Интерфейс - структура из двух указателей (type + value, 16 байт), поэтому передавать *MyInterface почти никогда не нужно. Это распространённая ошибка новичков. Передавайте интерфейс по значению - он уже легковесный.

Подробнее →
10 Где в Go рекомендуется определять интерфейс: в пакете с реализацией или в пакете-потребителе? 🟡 Средний
Ответ: B) В пакете-потребителе, где интерфейс используется; принцип "accept interfaces, return structs"

Go best practice: интерфейс определяется потребителем, а не реализацией. Пакет-реализация возвращает конкретный тип. Потребитель определяет минимальный интерфейс, который ему нужен.

Подробнее →
11 Когда интерфейсная переменная равна nil? 🔴 Сложный
Ответ: B) Когда и тип, и значение nil

Интерфейс хранит пару (тип, значение). Он nil только когда оба компонента nil. Частая ловушка: var p *MyStruct = nil; var i interface{} = p; i != nil - true! Потому что тип (*MyStruct) не nil.

Подробнее →
12 Скомпилируется ли: type S struct{}; func (s *S) String() string { return "s" }; var _ fmt.Stringer = S{}? 🔴 Сложный
Ответ: B) Нет, S{} не реализует Stringer

String() определён на *S (pointer receiver). Значение S{} имеет только value receiver методы, а *S - и value, и pointer. S не реализует Stringer, а *S реализует. Исправление: var _ fmt.Stringer = &S{}.

Подробнее →
13 Что произойдёт: var a, b any = []int{1}, []int{1}; fmt.Println(a == b)? 🔴 Сложный
Ответ: D) panic

Интерфейсы можно сравнивать оператором ==, и код скомпилируется. Но если конкретный тип внутри интерфейса не поддерживает сравнение (слайсы не сравнимы), произойдёт panic: comparing uncomparable type []int.

Подробнее →
14 Можно ли встроить интерфейс в структуру? 🔴 Сложный
Ответ: C) Да, но вызов методов вызовет panic, если не задать значение

Интерфейс можно встроить в структуру. Структура будет иметь все методы интерфейса и формально его реализовывать. Но если встроенному полю не присвоить конкретное значение, вызов метода приведёт к panic (nil pointer). Этот паттерн используется для декорирования.

Подробнее →
15 Как устроен непустой интерфейс внутри Go runtime? 🔴 Сложный
Ответ: B) Структура iface: указатель на itab (тип + методы) и указатель на данные

Непустой интерфейс - структура iface из двух указателей: itab (информация о типе + таблица методов) и data (указатель на значение). Пустой интерфейс (any) - структура eface: только _type + data. Размер интерфейса - 16 байт на 64-bit.

Подробнее →
16 Что выведет: var p *int = nil; var i interface{} = p; fmt.Println(i == nil)? 🔴 Сложный
Ответ: B) false

false! Интерфейс == nil только когда оба поля (type и value) равны nil. При присвоении *int(nil) интерфейсу, type заполняется (*int), а value = nil. Интерфейс 'знает' свой тип, поэтому не nil. Частая ловушка при возврате ошибок: return (*MyError)(nil) != nil как error.

Подробнее →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.