Employmentgolang

Golang на собесах: что тебе учить в первую очередь?

Подготовка к собесу на Go не сложная. Тебе лишь надо правильно приоретизировать темы, по которым ты будешь двигаться. В посте я помогу тебе разметить основные точки, на которые нужно делать особый упор. Статья содержит ссылки на материалы из базы, чтобы ты легко мог погрузиться тему не отходя от кассы.

24 сентября 2026 г.8 мин чтения0 комментариев

Синтаксис в Go очень простой. Вопросов по ней правда минимум, оригинальностью они совсем не отличаются. Хоть пул вопросов зависит от компании, но список часто очень сильно похож.

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

Самое сложное в домене многопоточки это та самая скуфовская база. Если ты понимаешь как работают потоки, ядра и память хотя бы на базовом уровне, то многопоточку ты поймешь очень легко. Однако поэтому она и настолько многоуровневая. Считай - это азы computer science, которые в нас очень активно запихивали на первых курсах универа.

Я часто буду ссылаться на внутренню базу вопросов и знаний, так что лови ссылки на них сразу: Roadmap, Вопросы.

Тренажер в базе научит тебя правильно отвечать на вопросы из базы и проходить собесы.

Многопоточка

Горутина это коробка, а поток - грузовик. В плюсах ты сам напихиваешь потоки задачами, и сам за ними следишь. А гошка позволяет не думать о грузовиках, создавая только задачи. Отсюда рождается эта знаменитая GMP модель.

  • G - горутина (коробка)
  • M - поток операционной системы (грузовик)
  • P - Логический процессор: контекст выполнения с локальной очередью горутин (погрузочная площадка)

Горутины распихиваюстся по логическим процессорам, а поток операционной системы разгребает их, выполняя весь тот контекст, что был в очереди.

Горутина это по сути управляемая задачка. У нее есть состояние, контекст выполнения и свой собственный небольшой стэк с кадрами вызовов. Ее можно, передавать с процессора на процессор, отправлять в очередь ожидающих, если надо получить HTTP ответ.

В этой же под-области валяются механизмы синхронизации. Нужны они для того, чтобы твои данные между горутинами передавались, и синхронизировались.

  • Channel - труба, в которую одна горутина данные запихивает, а другая достает. И это как бы потоко-безопастно, за одним исключением. Если канал не инициализирован, и ты попытался что то оттуда прочитать, то ты заблокирован навсегда. Если канал закрыт, и ты что-то туда пишешь, то программа упадет. И таких ЕСЛИ можно насчитать порядка 5.
  • Waitgroup - счетчик. .Add() счетчик увеличивает, Wait() ждет пока счетчик не упадет до нуля. Поэтому если main() горутина запустила себе 10 воркерков горутин, и должна их ждать, то ПЕРЕД запуском каждого работяги надо счетчик увеличивать, а когда работяга отработал - внутри него счетчик уменьшать. И дрочить тебя будут как раз на понимание этого процесса. Например, почему нельзя увеличить счетчик внутри горутины? Об этом можешь прочитать в блоке по многопоточке.
  • Мьютексы. Когда два потока меняют одну и ту же переменную, можно попасть в ситуация аля Data Race. Два потока столкнулись лбами, хотят изменить переменную, но друг о друге не знают. Мьютекс блокирует горутину в том случае, если его коллега УЖЕ с этой секцией работает.
  • Атомики. Современная тэкнолоджия привела нас к тому, что невероятно быстрые потоки могут АТОМАРНО работать с некоторыми типами данных. Увеличить счетчик, например, можно в одну операцию процессора, и тогда по сути никаких критических секций, где много потоков будут рыться в одной тарелке - не будет. Но возможно это только в том случае, если твой процессор это вообще поддерживает. Не часто копают в устройство процессора, просто ты должен знать что это и с чем его едят.

Загвоздка лишь в том, что в их основе так же лежит база Computer science. А весь этот синтаксический сахар на безлактозном лишь надстройка. Разберешься чем мьютексы отличаются от атомиков, и уже закроешь половину всех основных вопросов.

Начни с темы в роадмапе, и двигайся по ней. Если возникнет желание, можешь углубится в тему на других ресурсах 🙂

Для закрепления результата обязательно напиши свой worker pool: программа создает N горутин, которые ассинхронно ходят в очередь задач, разгребают ее, и результат печатают в консоль.

ТемаGoСредний уровеньКонкурентность в GoГорутины, планировщик GMP, локальные и глобальные очереди выполнения, work-stealing, обработка syscall и вытеснение в рантайме Go.

Лично мне база по C++ выстроила фундамент, на который абстракции по Golang легли как литые.

Контейнеры

Но правды ради, это не все. Следующий по списку относительно сложный аспект это контейнеры. В них ебанесся сколько нюансов. Но тебе надо в первую очередь понять эти три:

String

ЭТО НЕИЗМЕНЯЕМЫЙ МАССИВ БАЙТ. Не слайс, не список (которого даже нет в go). Хранит не символы, не секреты или еще какую нибудь дичь. Это именно голые байты, которые ты должен привести к другому виду для вывода в консоль.

Байт - это просто маленькое число от 0 до 255. Английской букве обычно хватает одного байта, а русской букве или эмодзи — нескольких.

Поэтому len("hello") вернёт 5, а len("привет")12: len считает байты, а не буквы.

Когда Go нужно прочитать строку как текст, он объединяет байты в руны.

Руна - это число, обозначающее одну букву, знак или другую единицу текста. Перебираешь строку через range — получаешь руны. Обращаешься через s[i] — получаешь отдельный байт. На собесе это спрашивают всегда.

Короче в Go для хранения символов используются байты, но для декодирования есть руны. Древнегреческие.

GO
func main() {
  s := "Привет"
  fmt.Println(len(s))         // 12 байт
  fmt.Println(len([]rune(s))) // 6 Unicode-кодовых точек
  fmt.Printf("%x\n", s[0])    // первый байт: d0
  fmt.Printf("%c\n", []rune(s)[0]) // первая rune: П
}

Строки массив байт, а массивы неизменямы. Поэтому просто добавить символ в уже созданную строку не выйдет. И интервьюер тебя обязательно об этом спросит.

ТемаGoСредний уровеньСлайсы, мапы и строкиВстроенные коллекции Go от основ до устройства — slice и его трёхсловный заголовок, выражения среза, рост и алиасинг, map с comma-ok и устройством hmap, nil-карта, строки как неизменяемые байты и безопасность памяти.

Массивы и Слайсы

Классический тупой вопрос - в чем разница этих двух контейнеров. Но по сути, массив статический, добавить туда элменты нельзя, а изменить можно.

Элементы слайса лежат в динамической памяти. Они могут быть перемещены, удалены, и выделены заново. Но нюансов тут хватает, и именно туда будут бить на интервью.

Слайс - это структура, которая хранит:

  • Текущее кол-во элементов
  • Максимальное количество элементов
  • Указатель на массив данных

Так вот, самый популярный вопрос:

Цитата

А че будет, если слайс в 3 элемента, у которого максимум может быть 5, передать в функцию по значению и добавить туда один новый элемент? Поменяется локальный, или переданный?

Разумеется если б ничего не менялось, тебе бы этот вопрос не задавали.

Поскольку указатель на массив данных внутри слайса передается так же по значению, то любые махинации с копией меняют и исходный массив. Но не всегда. Если максимального размера в слайсе хватает, то добавление нового элемента в копию изменит и исходник. Элемент появится. Но если место закончилось, то будет ре-аллокация: выделится новый массив, в который скопируются исходные данные. Короче тот еще мозговынос, и подробнее можешь прочитать на платформе.

GO
func add(s []int) {
  s = append(s, 4)
  fmt.Println("внутри:", s)
}

func main() {
  a := make([]int, 3, 5)
  copy(a, []int{1, 2, 3})
  add(a)
  fmt.Println("снаружи:", a)     // [1 2 3], len всё ещё 3
  fmt.Println("после reslice:", a[:4]) // [1 2 3 4]

b := []int{1, 2, 3} // len=3, cap=3
add(b)              // append создаст новый backing array
fmt.Println("снаружи:", b) // [1 2 3]

}
ТемаGoСредний уровеньСлайсы, мапы и строкиВстроенные коллекции Go от основ до устройства — slice и его трёхсловный заголовок, выражения среза, рост и алиасинг, map с comma-ok и устройством hmap, nil-карта, строки как неизменяемые байты и безопасность памяти.

Hash map

Его величество - map. Мапа это ассоциативная структура данных, где хранятся контейнеры, ака бакеты, и в бакетах лежат элементы. Каждый элемент это парочка твикс - ключ и значение. Чтобы найти значение, тебе нужен ключ.
Маппка перед добавлением нового элемента считает особое значение для ключа - хэш. Хэш же это число в несколько десятков циферок, которое по хорошему должно быть уникальным, но получается это не всегда. Поэтому существует такая штука, как хэш коллизии - в одном бакете у тебя валяется несколько элементов. Но решается это через разделение на две части.

Первая половина хэша выбирает бакет, в котором значение должно лежать. а вторая половина находит сам элемент внутри бакета.
Ну и вопросы на собесах очень часто про ток, как устроены эти бакеты, что такое овуляция эвакуация и т.д.

ТемаGoСредний уровеньСлайсы, мапы и строкиВстроенные коллекции Go от основ до устройства — slice и его трёхсловный заголовок, выражения среза, рост и алиасинг, map с comma-ok и устройством hmap, nil-карта, строки как неизменяемые байты и безопасность памяти.

Память

Ну и последнее в нашем небольшом дроч-топе - это память. Но не потому что альцгеймер, а потому что ребятки на интервью не могут внятно объяснить чем стэк отличается от кучи, и почему эскейп анализ вообще существует. Поясняю

У твоей программы есть два основных месте, где лежат твои переменные и структруы - стэк и куча. Все переменные, которые нельзя положить в стэк - кладутся в кучу.

Какие же переменные нельзя положить в стэк: Все те, что возвращаются из функции, передаются внутрь замыкания, т.е анонимной функции. Но это тоже не гарант. Нюансы можешь прочитать тут.

ТемаGoПродвинутый уровеньПамять в GoСтек против кучи, escape-анализ, принудительное размещение в куче, new против make и локальность кэша.

Вердикт же выводится на этапе компиляции. Собирается твоя программа, и компилятор Golang анализирует каждую переменную. Если все ок - остается в стэке, если нет - то попадает в кучу.

Две памяти нам надо по двум причинам. Стэк быстрее, но он статичен. Во время работы программы, ты память там не выделишь. Выделяется и чистится память там автоматически, каждый раз когда функция начинает и заканчивает свое выполнение. Оттуда и автоматика - функция вызвалась → выделила память → завершилась → освободила память. Поэтому и нагрузки на GC у тебя нет, и сами аллокации у тебя дешевые.

Куча - динамическая, но медленная. Че-то там выделить всегда стоит времени. Поэтому эскейп анализ настолько важная штука, что избавляет тебя от нужды задумываться о размещении данных. Ручками следить за памятью, как это происходит в C++ не приходится. Нужна переменная на стэке или в хипе - решает Golang.

Но каждый интервьюер хочет, чтобы ты знал его механизм.

ТемаGoПродвинутый уровеньПамять в GoСтек против кучи, escape-анализ, принудительное размещение в куче, new против make и локальность кэша.

Заключаем

С базой по гошке разобрались, в следующем посте обсудим базы данных и необходимую основу, чтобы фиксик на интервью тебе галочку все-же поставил.

Обнял, не теряйся.

Тегиgolang

Leave a comment

Войдите, чтобы оставить комментарий.

Create an account or log in to leave a comment.

Sign In

Comments

No comments yet.

05Похожие разборы

Все записи
Employment

Итак, ты перекатываешься в Golang...

Мир меняется, рынок меняется, зарплаты и вакансии тоже меняются. Возможно, и тебе пора? Глянем что нужно, чтобы разобраться в golang, подготовиться к собесам и получить оффер.

11 мин чтения29 августа 2026 г.
Employment

Почему никто не может найти работу в 2026 году

За последние 6 лет на Айти маркете были взлеты и падения. К сожалению, пик пришелся на 2020-2022 год, а сейчас мы переживаем ломку, когда на работу все так же хочется, но почему-то не можется. Я расскажу как тебе найти работу и почему работа не может найти тебя.

5 мин чтения15 сентября 2026 г.
Employment

Гайд по перекату. Фреймворк на случай, если ты заебался.

У всех приходит момент, когда нужно все поменять. Ты устал от работы, от компании, от менеджемента, от области, от своего языка программирования. Это не важно. Я дам тебе фреймворк как поменять все. Расскажу про свой опыт, предложу тебе решение через SMART, который я подкрепил собственным опытом.

11 мин чтения17 августа 2026 г.