Подготовка к собеседованию — Go-разработчик
Колода из 333+ карточек с вопросами для собеседования по направлению «Go-разработчик» — по темам и уровню сложности, с повторениями по вашим оценкам. Посмотрите несколько карточек ниже, затем выберите доступ, чтобы учить всё направление по расписанию в стиле Anki (SM-2).
Новым подписчикам месяца или года может быть доступно 7 дней бесплатно. Условия и сумму подтвердит страница оплаты.
С чего начать
Нужны основы синтаксиса Go, функций и структур. Модули Go дополнены общими SQL, инфраструктурой, проектированием систем и бэкендом; в части общих примеров есть Python и команды оболочки.
Первый проход: Основы языка: слайсы, мапы и строки → Интерфейсы и система типов. Начните с базовых вопросов в этих модулях, затем продолжайте по плану. К сложным и senior-вопросам возвращайтесь по требованиям вакансии; все карточки доступны с самого начала.
Общие темы могут входить в несколько направлений и сохраняют одну историю повторений. План ниже отмечает общие основы и профильные модули; выбирайте глубину под свою вакансию.
Что внутри
Все темы направления, сгруппированные так, как вы будете их учить.
Основы языка: слайсы, мапы и строки
15 карточекПрофильный модуль
Интерфейсы и система типов
6 карточекПрофильный модуль
Ошибки, defer и panic
7 карточекПрофильный модуль
Горутины, каналы и select
12 карточекПрофильный модуль
sync, atomic и context
12 карточекПрофильный модуль
Планировщик, GC и память
8 карточекПрофильный модуль
Паттерны конкурентности (live-coding)
8 карточекПрофильный модуль
Тестирование, тулинг и дженерики
7 карточекПрофильный модуль
Базы данных
104 карточкиОбщие основы
DevOps и инфраструктура
35 карточекОбщие основы
Системный дизайн
29 карточекОбщие основы
Распределённые системы
12 карточекОбщие основы
Kafka и очереди
12 карточекОбщие основы
Кэширование вглубь
10 карточекОбщие основы
Производительность и конкурентность
11 карточекОбщие основы
Надёжность и инциденты
10 карточекОбщие основы
Поведенческое интервью
35 карточекОбщие основы
Примеры вопросов
Несколько карточек из колоды — откройте ответ, затем выберите доступ, чтобы учить весь набор по расписанию.
Чем слайс отличается от массива и как слайс устроен под капотом?
Чем слайс отличается от массива и как слайс устроен под капотом?
Короткий ответ: Массив ([N]T) содержит фиксированное число элементов; длина входит в его тип. Присваивание массива копирует элементы. Слайс ([]T) описывает окно в общем базовом массиве (backing array), поэтому присваивание слайса оставляет этот массив общим.
Подробно:
- Слайс удобно представлять как
{указатель, len, cap}: указатель задаёт первый элемент,len— число видимых элементов,cap— насколько можно расширить слайс от этой позиции без нового массива. arr[1:3]включает индексы 1 и 2. Верхняя граница не включается. Для массива из пяти элементов длина такого слайса равна 2, ёмкость — 4.- В стандартной реализации дескриптор занимает три машинных слова: обычно 24 байта на 64-битной системе и 12 на 32-битной. Это деталь реализации, а не основание зашивать размер в код.
arr := [5]int{0, 1, 2, 3, 4}
s := arr[1:3] // [1 2], len=2, cap=4
copyOfArray := arr
alias := s
alias[0] = 9
fmt.Println(arr, copyOfArray, s)
// [0 9 2 3 4] [0 1 2 3 4] [9 2]
Важно: Копирование массива копирует элементы, но не объекты, на которые ссылаются элементы-указатели, мапы или слайсы. Размещение памяти массива и слайса зависит от escape analysis компилятора.
Источники: Документация Go 1, Документация Go 2.
Как в Go реализован полиморфизм без классов и наследования?
Как в Go реализован полиморфизм без классов и наследования?
Короткий ответ: Интерфейс задаёт поведение через сигнатуры методов. Любой тип с нужным набором методов реализует его неявно. Функция, принимающая этот интерфейс, работает с разными конкретными типами, а вызов метода использует реализацию сохранённого динамического значения.
type Speaker interface{ Speak() string }
type Cat struct{}
type Dog struct{}
func (Cat) Speak() string { return "meow" }
func (Dog) Speak() string { return "woof" }
func announce(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
announce(Cat{}) // meow
announce(Dog{}) // woof
}
Подробно: Сигнатуры должны совпадать; объявление implements не нужно. Соответствие проверяется статически в местах присваивания и передачи аргументов, а вызовы через интерфейс могут выбирать реализацию динамически. Предпочитайте маленькие интерфейсы, описывающие потребности вызывающей стороны.
Встраивание — отдельный инструмент: один тип включается в другой, а его методы могут продвигаться наружу. Внешний тип не становится подтипом встроенного, и переопределения методов как в классах нет. Инкапсуляция на уровне пакетов управляется экспортируемыми именами, начинающимися с заглавной буквы Unicode.
Важно: «В Go нет наследования классов» не означает «в Go нет динамической диспетчеризации». Её дают интерфейсные вызовы. Само по себе встраивание не заставляет метод внутреннего значения вызывать одноимённый внешний метод.
Источники: Документация Go 1, Документация Go 2.
Когда функция должна вернуть error, а когда — паниковать?
Когда функция должна вернуть error, а когда — паниковать?
Короткий ответ: Возвращай error для сбоев, которые вызывающий код должен обрабатывать: неверный ввод, отсутствующий файл, таймаут или недоступную зависимость. Panic оставь для ошибок программиста, нарушений инвариантов или API, которое документированно паникует.
Примеры: Парсер возвращает error для некорректного пользовательского ввода. Helper MustParse может намеренно паниковать при инициализации с фиксированным значением разработчика. Рантайм также паникует при некоторых некорректных операциях, например выходе индекса за границы.
Паника выполняет defer при раскрутке текущей горутины. Если она дошла до вершины горутины без recover, процесс завершается. Восстановление на осознанной границе может локализовать сбой — например, HTTP-сервер обрабатывает панику handler, — но нельзя выдавать неудачную операцию за успешную или считать общее состояние гарантированно целым.
Механизм не равен тяжести: Обычная возвращённая ошибка тоже может быть фатальной для приложения. Паника не доказывает повреждение всего процесса. Выбирай контракт API и границу восстановления по тому, что безопасно продолжать; не добавляй blanket recover в каждую горутину и не используй panic для обычной валидации.
Подробнее: Документация Go · Документация Go
Чем горутина отличается от потока ОС?
Чем горутина отличается от потока ОС?
Короткий ответ: Горутина — конкурентное выполнение, которым управляет рантайм Go. Поток ОС планируется операционной системой. Go распределяет множество горутин по потокам ОС, а стек каждой горутины может расти и уменьшаться.
Подробно:
- Горутина запускается через
go f(). Вызывающий код продолжает работу без ожидания; если завершение важно, нужна явная синхронизация. - Стек горутины начинается с небольшого размера (исторически около 2 КиБ в стандартном рантайме). Начальный размер и политика роста — детали реализации. Размер стека потока ОС зависит от платформы и настроек.
- Когда горутина блокируется на канале или поддерживаемом сетевом I/O, рантайм может выполнить другую горутину на доступном потоке. Блокирующие системные вызовы и cgo могут потребовать дополнительных потоков ОС.
- Планирование рантаймом обычно дешевле создания отдельного потока ОС на задачу. Точная стоимость и допустимое число зависят от нагрузки; горутины всё равно занимают память и удерживают объекты по ссылкам.
done := make(chan struct{})
go func() {
fmt.Println("work")
close(done)
}()
<-done // дождаться завершения этой горутины
Важно: Конкурентность означает возможность независимого продвижения задач, параллелизм — одновременное выполнение. Горутины дают конкурентность; число CPU и GOMAXPROCS ограничивают параллельное выполнение Go-кода. Возврат из main завершает программу без ожидания других горутин.
Источники: Документация Go 1, Документация Go 2.
В чём разница между sync.Mutex и sync.RWMutex и когда RWMutex реально оправдан?
В чём разница между sync.Mutex и sync.RWMutex и когда RWMutex реально оправдан?
Короткий ответ: Mutex допускает одну критическую секцию одновременно. RWMutex позволяет нескольким читателям работать под RLock, а Lock исключает и читателей, и других писателей. Начни с простого замка; выбирай RWMutex, когда измерения показывают пользу параллельного чтения.
Как рассуждать: Все обращения к защищаемому инварианту должны использовать один замок. Под RLock можно только читать: изменение позиции LRU или ленивая инициализация поля — уже запись. Нельзя повысить RLock до Lock; повторный захват RLock может привести к deadlock, если писатель уже ждёт.
Ожидающий писатель блокирует новых читателей до своего захвата и освобождения замка. Это устраняет один источник голодания писателя, но не гарантирует справедливое планирование или максимальное время ожидания.
Пример: Длительное чтение конфигурации может выиграть от параллельных читателей. Короткий инкремент счётчика — не обязательно. Универсального соотношения чтений и записей нет: измеряй реальную нагрузку.
Подробнее: Документация Go
Что задаёт GOMAXPROCS и чему он равен по умолчанию?
Что задаёт GOMAXPROCS и чему он равен по умолчанию?
Короткий ответ: GOMAXPROCS ограничивает число потоков ОС, одновременно исполняющих Go-код. Он не ограничивает число горутин, потоков в блокирующих syscall или конкурентных I/O-операций.
Значение по умолчанию зависит от версии: До Go 1.25 это было число логических CPU, доступных при старте. Go 1.25+ также может учитывать CPU affinity и, на Linux, cgroup-лимит CPU, периодически обновляя значение. Настройки совместимости для старой версии языка в модуле могут сохранять прежнее поведение.
Текущий рантайм обычно выбирает минимум из числа CPU, affinity и округлённой вверх квоты cgroup, но только из-за квоты не опускается ниже двух. Это деталь реализации: GOMAXPROCS не равен Kubernetes CPU requests и не всегда равен runtime.NumCPU().
n := runtime.GOMAXPROCS(0) // прочитать без изменения
fmt.Println(n)
Переменная окружения или runtime.GOMAXPROCS(n) с положительным значением отключают автоматические обновления. В Go 1.25+ runtime.SetDefaultGOMAXPROCS() восстанавливает значение рантайма и обновления. При диагностике throttling проверяй toolchain, версию модуля и GODEBUG.
Подробнее: Документация Go · Документация Go
Готовы лучше запоминать?
Посмотрите пример, выберите направление и настройте регулярную практику под свою подготовку.
Вопросы об этом направлении
Как готовиться к собеседованию на «Go-разработчик»?
Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «Go-разработчик» в RecallDeck даёт 333+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2), основанному на ваших оценках — чтобы тренировать вспоминание и объяснение. Дополняйте повторения кодингом и пробными собеседованиями.
Какие темы охватывает направление «Go-разработчик»?
Направление «Go-разработчик» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.
Помогает ли интервальное повторение в подготовке к «Go-разработчик»?
Да. Активное вспоминание и честная самооценка помогают закреплять знания. RecallDeck назначает повторения карт по направлению «Go-разработчик» на основе ваших оценок: знакомые карты возвращаются реже, а сложные получают больше практики.
Можно попробовать направление «Go-разработчик» до оплаты?
Новым подписчикам месячного или годового тарифа может быть доступен пробный период семь дней со всем направлением «Go-разработчик» и всеми функциями. Право на него и сумму подтвердит страница оплаты; при повторной подписке списание может быть сразу. Отмените подписку онлайн до конца пробного периода, чтобы избежать первого списания. У вечного доступа пробного периода нет.