Співбесіда Go фокусується на горутинах, каналах, інтерфейсах та обробці помилок — мова маленька, тому питання йдуть углиб, а не вшир. Нижче — найчастіші з еталонними відповідями.
До кожного питання — еталонна відповідь, з якою можна порівняти свою.
1
Що таке горутина і чим вона відрізняється від потоку ОС?
Відповідь
Горутина — це функція, яку планує рантайм Go, а не операційна система. Вона стартує з крихітним стеком у пару кілобайтів, що росте за потреби, тоді як потік ОС резервує мегабайти, тому програма спокійно тримає сотні тисяч горутин. Рантайм мультиплексує їх на невеликий пул потоків ОС і перемикає в точках блокування без перемикання контексту ядра.
2
У чому різниця між буферизованим і небуферизованим каналом?
Відповідь
Небуферизований канал синхронний: відправник блокується, доки не буде готовий отримувач, тому він заразом працює точкою синхронізації. Буферизований приймає значення до розміру буфера без очікуючого отримувача і блокується лише при заповненні. Небуферизований беруть, коли потрібна гарантія передачі, буферизований — щоб згладити сплески, але великий буфер частіше ховає проблему в дизайні, ніж вирішує її.
3
Як працює select? Що станеться, якщо готові кілька case?
Відповідь
select чекає кількох операцій з каналами і продовжує з тією, що готова. Якщо готові одразу декілька, вибір робиться рівномірно випадково, що не дає жодному case голодувати. Гілка default перетворює конструкцію на неблокуючу, а select взагалі без case блокується назавжди — інколи це використовують навмисно, щоб «припаркувати» горутину.
4
Поясніть різницю між слайсом і масивом. Як працює append?
Відповідь
У масиву фіксована довжина, що входить у його тип, і він копіюється за значенням. Слайс — це заголовок з вказівником на підлеглий масив, довжиною та ємністю, тому при передачі копіюється лише заголовок. append пише у вільну ємність, якщо місце є; інакше виділяє більший масив і копіює, через що повернений слайс може більше не поділяти памʼять з вихідним — і тому результат append завжди треба присвоювати.
5
Що таке інтерфейс у Go? Чому їх називають імпліцитними?
Відповідь
Інтерфейс — це набір сигнатур методів; будь-який тип, у якого ці методи є, задовольняє його без жодного оголошення. Саме це й означає імпліцитність — немає ключового слова implements, тому інтерфейс можна оголосити в пакеті-споживачі, і наявні типи йому вже відповідають. Ідіоматична порада: тримати інтерфейси маленькими й оголошувати їх там, де використовують, а не поруч із реалізацією.
6
Як обробляти помилки в Go? Що таке error wrapping через %w?
Відповідь
Помилки — звичайні значення, що повертаються поруч із результатом і перевіряються явно в кожному місці виклику. Загортання через fmt.Errorf з дієсловом %w зберігає вихідну помилку всередині нового повідомлення, тому код-викликач досі може застосувати errors.Is для перевірки на сентинел або errors.As для видобування типізованої помилки. Загортання додає контекст у міру підйому помилки, не позбавляючи її програмної перевірності.
7
Що таке context.Context і навіщо він потрібен?
Відповідь
Context переносить сигнал скасування, дедлайн і значення рівня запиту через межі API. Коли клієнт відключився або спрацював таймаут, скасування контексту поширюється на всі похідні горутини, тож запити до бази й HTTP-виклики перериваються, а не витікають. За домовленістю його передають першим параметром і ніколи не зберігають у структурі.
8
Що таке defer? У якому порядку виконуються відкладені виклики?
Відповідь
defer планує виклик на момент виходу з функції, незалежно від того, яким шляхом або через яку паніку вона завершилася. Відкладені виклики виконуються в порядку «останній прийшов — перший вийшов», тобто останній defer спрацьовує першим. Аргументи обчислюються в момент запису defer, а не при виконанні — частий джерело сюрпризів, коли відкладають виклик, що захоплює змінну циклу.
9
Як уникнути race condition? Mutex чи канали?
Відповідь
Гонка даних — це несинхронізований конкурентний доступ, де хоча б одна сторона пише, і вона детектується прапорцем -race. sync.Mutex беруть, коли горутини ділять шматок стану і треба просто серіалізувати доступ до нього. Канали беруть, коли володіння даними передається між горутинами — правило звучить як «діліться памʼяттю через спілкування, а не спілкуйтеся через спільну памʼять».
10
Що таке nil-інтерфейс і чому порівняння з nil може здивувати?
Відповідь
Значення інтерфейсу складається з двох слів: типу та значення. Воно дорівнює nil лише коли обидва слова nil. Якщо присвоїти інтерфейсу nil-вказівник конкретного типу, слово типу заповнюється, і інтерфейс виявляється не-nil, хоча сам вказівник nil. Це класичний баг, коли функція повертає nil *MyError як error, і перевірка err != nil у викликача несподівано проходить.
🦎
Прочитати відповіді недостатньо
На співбесіді ти говориш вголос під тиском. Кем поставить ті самі питання, оцінить кожну відповідь і покаже, що саме підтягнути.
Пройти інтерв'ю Go Backend →Безкоштовно · 3 інтерв'ю на місяць