Как устроены срезы и мапы, чем интерфейсы Go отличаются от привычных, почему ошибки — это значения, как работают горутины, каналы, select и context — то, о чём спрашивают начинающих Go-разработчиков.
- Что такое any, type assertion и type switch? Junior
any (= interface{}) — интерфейс без методов, ему удовлетворяет любой тип. Достать конкретный тип — type assertion v, ok := x.(string) (без ok при несовпадении — panic) или type…
- Почему изменение одного среза неожиданно меняет другой? Junior
Срезы, полученные друг из друга, делят базовый массив, пока append не перевыделил его. Если у исходного среза есть свободная ёмкость, append к подсрезу перезапишет элементы…
- Чем массив отличается от среза в Go? Junior
Массив [5]int — значение фиксированного размера, размер — часть типа ([3]int и [4]int — разные типы); присваивание и передача копируют все элементы. Срез []int — дескриптор над…
- Чем буферизованный канал отличается от небуферизованного и что происходит при закрытии канала? Junior
Небуферизованный канал — отправка блокируется, пока получатель не заберёт значение: синхронная встреча. Буферизованный (make(chan T, n)) — отправка блокируется только при полном…
- Зачем нужен context.Context? Junior
Context переносит отмену, дедлайн и значения запроса через цепочку вызовов и горутин. Создают от входящего запроса, передают первым аргументом во все функции с вводом-выводом…
- Как работает defer и в каком порядке выполняются отложенные вызовы? Junior
defer откладывает вызов до выхода из функции — при обычном return и при panic. Отложенные вызовы выполняются в порядке LIFO (последний — первым). Аргументы вычисляются сразу в…
- Как в Go обрабатывают ошибки и зачем нужны errors.Is, errors.As и %w? Junior
Ошибка — обычное значение типа error, которое функция возвращает последним: if err != nil { return ... }. Оборачивают с контекстом через fmt.Errorf("...: %w", err). Проверяют…
- Как в Go устроены сборка мусора и размещение на стеке или в куче? Middle
GC в Go — конкурентный mark-and-sweep без поколений и без перемещения объектов, с паузами в доли миллисекунды. Где разместить значение, решает escape analysis компилятора: не…
- Как устроены дженерики в Go и когда их использовать? Middle
С Go 1.18 функции и типы принимают параметры типов с ограничениями — интерфейсами, которые могут перечислять допустимые типы: func Max[T cmp.Ordered](a, b T) T. Применение …
- Что такое утечка горутин и как её избежать? Middle
Горутина, навсегда заблокированная на канале, мьютексе или вводе-выводе, никогда не завершится и держит стек и всё, на что ссылается. Типичные причины: отправка в канал, который…
- Что такое горутина и чем она отличается от потока ОС? Junior
Горутина — лёгкий поток, управляемый рантаймом Go: стартовый стек ~2 КБ (растёт по необходимости), создание и переключение в разы дешевле потока ОС — можно держать сотни тысяч…
- Как работают интерфейсы в Go и что значит неявная реализация? Junior
Тип удовлетворяет интерфейсу автоматически, если у него есть все методы интерфейса — без слова implements. Поэтому интерфейсы объявляют у потребителя и делают маленькими…
- Что изменилось с переменной цикла в Go 1.22? Junior
До Go 1.22 переменная цикла for i := ... была одна на весь цикл: замыкания и горутины, захватившие её, видели последнее значение. С Go 1.22 каждая итерация получает свою копию …
- Чем make отличается от new в Go? Junior
new(T) выделяет нулевое значение любого типа и возвращает указатель T. make — только для срезов, мап и каналов: инициализирует их внутреннюю структуру и возвращает само значение…
- Как устроена map в Go и какие у неё особенности? Junior
map — хеш-таблица: вставка, поиск и удаление в среднем O(1). Порядок обхода случаен и намеренно перемешивается от запуска к запуску. Конкурентная запись из нескольких горутин …
- Как устроены модули Go — go.mod, go.sum, версии? Junior
go.mod объявляет путь модуля, версию Go и зависимости с версиями (семантическое версионирование). go.sum хранит хеши — гарантия, что скачан тот же код. Версии выбирает MVS…
- Когда использовать каналы, а когда sync.Mutex и WaitGroup? Junior
Каналы — для передачи данных и владения ими между горутинами (конвейеры, очереди задач). Mutex — для защиты общего состояния (кэш, счётчик). WaitGroup — дождаться группы горутин…
- Почему интерфейс с nil-указателем внутри не равен nil? Middle
Интерфейсное значение — пара (тип, значение). Оно равно nil, только когда обе части nil. Если положить в интерфейс nil-указатель конкретного типа, тип уже заполнен — интерфейс не…
- Чем nil-срез отличается от пустого и почему запись в nil-map вызывает panic? Junior
nil-срез (var s []int) и пустой ([]int{}) оба имеют len 0, с обоими работают range и append. Различие — только s == nil и JSON: nil кодируется как null, пустой — как []. nil-map…
- Когда в Go используют panic и как работает recover? Junior
panic — для невозможных ситуаций и ошибок программиста (выход за границы, nil-указатель, нарушенный инвариант), а не для ожидаемых ошибок. Panic раскручивает стек, выполняя defer…
- Как в Go передаются аргументы и зачем нужны указатели? Junior
Всё передаётся по значению — копируется само значение: структура целиком, массив целиком. Чтобы функция изменила объект вызывающего, передают указатель (T, взять адрес — &x)…
- Что такое гонка данных в Go и как её найти? Junior
Гонка данных — две горутины обращаются к одной переменной одновременно, и хотя бы одна пишет, без синхронизации. Результат непредсказуем, а для мап и срезов возможна порча…
- Как работает select в Go? Junior
select ждёт сразу несколько операций с каналами и выполняет ту, что готова первой; если готовы несколько — случайную. Ветка default делает select неблокирующим. Таймаут — ветка…
- Чем := отличается от var и что такое затенение переменных? Junior
:= — короткое объявление с выводом типа, только внутри функций; объявляет хотя бы одну новую переменную слева. var — работает и на уровне пакета, позволяет указать тип без…
- Как устроен срез (slice) в Go? Junior
Срез — дескриптор из трёх полей: указатель на базовый массив, длина (len — сколько элементов доступно) и ёмкость (cap — сколько поместится до конца массива). append пишет в тот же…
- Как в Go устроены строки, байты и руны? Junior
Строка — неизменяемая последовательность байт, обычно в UTF-8. len возвращает число байт, а не символов: кириллица занимает 2 байта, поэтому len("привет") == 12. Руна (rune =…
- Как в Go обходятся без наследования — что такое встраивание (embedding)? Junior
Наследования нет. Встраивание — поле без имени: методы и поля встроенного типа продвигаются во внешний и вызываются напрямую. Это композиция, а не наследование: нет…
- Как пишут тесты в Go — табличные тесты, моки, бенчмарки? Junior
Тесты — функции TestXxx(t testing.T) в файлах _test.go, запуск go test ./.... Идиома — табличные тесты: срез случаев и t.Run для каждого. Зависимости подменяют через маленькие…
- Когда метод должен иметь получатель-указатель, а когда — значение? Junior
Указатель func (s Svc) — если метод меняет получателя, структура большая или содержит то, что нельзя копировать (sync.Mutex). Значение func (p Point) — для маленьких неизменяемых…
- Чем Go отличается от других языков и почему его выбирают для бэкенда? Junior
Go — компилируемый статически типизированный язык с простым синтаксисом, сборщиком мусора и встроенной конкурентностью (горутины и каналы). Компилируется в один статический…
- Что такое нулевые значения в Go? Junior
Любая переменная без явной инициализации получает нулевое значение своего типа: 0 для чисел, "" для строк, false для bool, nil для указателей, срезов, мап, каналов, функций и…