Библиотека Go для собеса | вопросы с собеседований
رفتن به کانال در Telegram
Вопросы с собеседований по Go и ответы на них. Покажем, как запустить своего ии-агента: https://clc.to/tvpmD По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot Наши каналы: https://t.me/proglibrary/9197
نمایش بیشتر7 431
مشترکین
-224 ساعت
-127 روز
+930 روز
آرشیو پست ها
❓ Почему interface{} или any замедляют программу
Любой интерфейс в Go — это два указателя. Пустой интерфейс (eface) хранит указатель на метаданные типа и указатель на данные. Непустой (iface) — указатель на itab (таблицу с информацией о типе и методах) и указатель на данные.
Само по себе это не проблема. Проблемы возникают из-за последствий такого устройства.
Когда вы передаёте конкретное значение в интерфейс, компилятор запускает escape analysis — анализ, может ли значение убежать за пределы текущего стекового фрейма. Если да, значение копируется в кучу, а указатель смотрит на эту копию.
Простые типы: int, bool, указатели; компилятор нередко передаёт без аллокации. Но структуры и значения, которые реально убегают, аллоцируются. Это означает нагрузку на GC.
Вызов метода через интерфейс это косвенный вызов через
itab.fun[].
Компилятор не знает во время компиляции, какая именно функция будет вызвана, поэтому:
• Компилятор не может подставить тело функции на месте вызова
• Процессор видит косвенный переход и не может надёжно его предсказать
• Перед вызовом нужно прочитать адрес функции из itab
Это не катастрофа при редких вызовах, но в циклах с миллионами итераций разница ощутима.
🐸 Библиотека Go для собеса❓ Какие типы можно передавать в unique.Make
Только comparable типы, которые поддерживают
==. Срезы, мапы и функции не подойдут, компилятор не пропустит.
🐸 Библиотека Go для собеса❓ Почему GOPATH уступил место Go модулям
GOPATH просто брал тот код, что уже лежал на вашей машине. Склонировали проект на другом компьютере — и зависимости уже другие. Воспроизводимость сборки не гарантирована.
Go модули решают эту проблему в корне: каждая зависимость зафиксирована с конкретной версией, а файл go.sum хранит криптографические хэши. При загрузке зависимостей Go сверяется с ним и гарантирует, что вы получаете ровно тот же код, что использовался при разработке.
🐸 Библиотека Go для собеса
Кажется, мы окончательно перешли от игрушек к суровому AgentOps
Приглашаем на наш обновлённый курс по разработке ИИ-агентов. Никакой воды про «будущее нейросетей», только инженерный подход.
На курсе мы:
— пошагово строим готовые системы на
LangGraph, CrewAI и MCP;
— настраиваем кэширование и роутинг, чтобы бот не сожрал токены;
— разбираемся со стейтом, учимся дебажить через time-travel и прикручиваем human-in-the-loop;
— выводим RAG в прод так, чтобы безопасники не завернули архитектуру из-за 152-ФЗ.
В пекло скучные лекции про общую инфраструктуру — сразу фокусируемся на агентных фреймворках и написании кода. Занятия ведут бывалые лиды из Газпромбанка и Альфы, набившие шишки на реальных задачах.
Кстати, на днях мы пилили агента в прямом эфире, если пропустили — есть запись вебинара.Сегодня последний день, когда можно забрать курс по старым ценам. Базовый тариф сейчас стоит 49 000 ₽ (вместо 62 990 ₽), продвинутый трек — 99 000 ₽ (вместо 124 990 ₽). Если не хочется отдавать всю сумму сразу, есть рассрочка. Торопитесь — на потоке осталось всего 5 мест! → Зафиксировать цену и перейти к сборке своих агентов
❓ Что такое unique.Handle и зачем он нужен
unique.Handle[T] — это обёртка над значением типа T, которая гарантирует что два одинаковых значения всегда дадут один и тот же Handle. Это позволяет сравнивать значения через == вместо reflect.DeepEqual или побайтового сравнения.
import "unique"
h1 := unique.Make("hello")
h2 := unique.Make("hello")
fmt.Println(h1 == h2) // true — один и тот же указатель внутри
🐸 Библиотека Go для собеса❓ Как вам вопросы прошедшей недели
Оцените их по шкале 🔥,❤️,👍,😢, 🥱,
где 🔥 — это супер, а 🥱 — это скучно.
Также приветствуется фидбек в комментах.
🐸 Библиотека Go для собеса
❓ Что может остановить горутину
time.Sleep(d) — усыпляет горутину на нужное время. Классика, когда надо подождать.
runtime.Gosched() — временно приостанавливает текущую горутину и передаёт управление планировщику, чтобы другие горутины могли выполниться.
runtime.Goexit() — завершает горутину немедленно, но аккуратно: все defer-ы выполнятся перед выходом.
Блокировка на канале — горутина ждёт, пока кто-то не отправит или не прочитает данные. Естественная синхронизация.
sync.Mutex — вызов Lock() блокирует горутину, пока мьютекс занят кем-то другим. Защита общих данных.
context.Context — горутина слушает ctx.Done() и останавливается, когда контекст отменяется или истекает таймаут.
🐸 Библиотека Go для собеса❓ Что возвращает context.AfterFunc и как отменить запланированную функцию
AfterFunc возвращает функцию stop(). Если вызвать её до того, как коллбэк начал выполняться, он будет отменён.
stop := context.AfterFunc(ctx, func() {
// cleanup
})
if stopped := stop(); stopped {
fmt.Println("Callback cancelled before execution")
}
stop() возвращает true — функция остановлена до запуска.
stop() возвращает false — функция уже выполняется или была остановлена ранее.
🐸 Библиотека Go для собесаСамый востребованный навык в ИТ в 2026-м — навык создания ИИ-агентов
Мы полностью переработали курс «Разработка AI-агентов» под реалии 2026 года. Никакой долгой теории — с самого начала пишем код. Обучать и делиться набитыми шишками будут эксперты-практики из Газпромбанка, Альфа-Банка и других бигтехов.
В программе:
— архитектура автономных систем с тестированием, ReAct-циклами и контролем токенов;
— практическая работа с актуальными фреймворками LangGraph, AutoGen, MCP и CrewAI;
— настройка продвинутого RAG для парсинга документов и точного поиска;
— внедрение решений с учётом действующего законодательства (152-ФЗ);
— дипломная работа, за основу которой можно взять свой рабочий проект или задачу, которую предложим мы.
Эксперты поделятся инсайтами из реального продакшна — тем, о чём вам никогда не расскажет ни одна нейросеть.
Запись первого открытого вебинара, на котором мы вместе с руководителем AI-направления в Альфа-Банке Полиной Полуниной пилили агента в прямом эфире.Ах да, чуть не забыли! Дарим промокод AGENTSWEB на скидку 10 000 рублей и два курса сверху при покупке до 15 марта 🎁 → Стать AI-инженером
❓ Нужно ли лочить структуру мьютексом, если идёт конкурентная запись в разные поля
Короткий ответ — да. Структуры в Go не потокобезопасны по умолчанию. Даже если две горутины пишут в разные поля, без синхронизации возникает гонка данных.
type Data struct {
Field1 int
Field2 int
mu sync.Mutex
}
// горутина 1
d.mu.Lock()
d.Field1 = i
d.mu.Unlock()
// горутина 2
d.mu.Lock()
d.Field2 = i
d.mu.Unlock()
Мьютекс гарантирует, что в любой момент только одна горутина имеет доступ к структуре. Без него поведение программы непредсказуемо — go race detector это подтвердит.
Обойтись без мьютекса можно только если поля полностью независимы и нет никаких побочных эффектов. Но это требует уверенности в контексте, а не предположений.
🐸 Библиотека Go для собеса❓ Что произойдёт, если вызвать context.AfterFunc на уже отменённом контексте
Функция выполнится немедленно в новой горутине, без ожидания. Проверять состояние контекста заранее не нужно, AfterFunc сам это обрабатывает.
ctx, cancel := context.WithCancel(context.Background())
cancel() // уже отменён
context.AfterFunc(ctx, func() {
fmt.Println("Runs immediately")
})
🐸 Библиотека Go для собеса❓ Зачем может понадобиться context.WithoutCancel
context.WithoutCancel нужен, когда у вас есть операция, которая обязана завершиться независимо от того, был ли отменён родительский контекст.
Типичная проблема без него:
func handleRequest(ctx context.Context) {
doWork(ctx)
saveAuditLog(ctx) // ctx уже отменён — лог не запишется!
}
Когда клиент отключился или истёк таймаут, ctx отменяется, и все операции на нём падают с context.Canceled. Но некоторые вещи отменять нельзя.
Вот так это можно обойти:
func handleRequest(ctx context.Context) {
doWork(ctx)
safeCtx := context.WithoutCancel(ctx)
saveAuditLog(safeCtx) // выполнится в любом случае
}
WithoutCancel создаёт копию контекста, которая наследует values и deadline, но игнорирует отмену родителя.
🐸 Библиотека Go для собеса❓ Что делает context.AfterFunc
context.AfterFunc планирует выполнение функции после завершения контекста — по отмене или таймауту. Функция запускается в новой горутине сразу после того, как ctx.Done() закрывается.
ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel()
context.AfterFunc(ctx, func() {
fmt.Println("Cleanup after context is done")
})
Типичные сценарии — очистка ресурсов, логирование, завершение фоновых операций.
🐸 Библиотека Go для собеса⏳ Часовая готовность: создаём ИИ-агента в прямом эфире
В 19:00 МСК в рамках нашего курса «Разработка AI-агентов» стартует вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке.
Будет live-демо работающего агента, реальные метрики из корпоративной среды и честный разбор архитектурных граблей — без воды и «успешного успеха».
Всем зрителям эфира дадим эксклюзивный промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.
👉 Занять место на вебинаре
☝️ Уже сегодня: ИИ-агенты в продакшене — инженерный подход к интеграции LLM
Индустрия активно обсуждает потенциал нейросетей, способных автоматизировать бизнес-процессы и заменить целые отделы. Однако реальное внедрение агентов в
production вскрывает серьёзные проблемы: разработчикам приходится бороться с непредсказуемыми галлюцинациями моделей, нестабильными API и сложной интеграцией в существующую архитектуру.
Сегодня в 19:00 МСК в рамках нашего курса «Разработка AI-агентов» мы проведём открытый вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке. Будем говорить о нейросетях с позиции жёсткой инженерии.
Разберём три реальных кейса из сурового банковского энтерпрайза, напишем и запустим агента прямо в эфире, честно обсудим грабли, на которые наступает бизнес при интеграции LLM.
Тем, кто придёт на эфир, дадим промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.
👉 Занять место на вебинаре❓ Что происходит с типом переменной в type switch при сравнении с nil
Когда вы используете type switch и ловите случай с nil, переменная примет тип исходного значения, которое вы проверяете. Не nil и не какой-то магический тип, а именно тот же тип, что и у интерфейса, с которым вы работаете.
Вот это не сработает:
var x any
var y error
switch t := x.(type) {
case nil:
y = t // Ошибка компиляции
}
Компилятор выругается, что any не может быть присвоен error, потому что any не имеет метода Error. Это подтверждает, что t внутри case nil имеет тип any, а не что-то другое.
🐸 Библиотека Go для собеса❓ Почему time.After в цикле может привести к утечке памяти и как это исправить
time.After создает таймер, который остается в памяти до истечения времени. Если вызывать это в цикле часто, таймеры накапливаются:
for {
select {
case event := <-ch:
handle(event)
case <-time.After(15 * time.Minute):
fmt.Println("timeout")
}
}
При большом потоке событий каждый цикл создает новый таймер на 15 минут, и они все висят в памяти одновременно. Это утечка.
Решение — использовать time.NewTimer и явно его останавливать:
timer := time.NewTimer(15 * time.Minute)
select {
case event := <-ch:
handle(event)
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
fmt.Println("timeout")
}
timer.Stop() освобождает ресурсы.
🐸 Библиотека Go для собеса❓ Часто используют пустую структуру в качестве ключа контекста. Почему это лучше, чем просто взять строку
Дело в том, что строки как ключи контекста создают проблему конфликтов имён. Если несколько пакетов используют одну и ту же строку, например
userID, они будут обращаться к одному и тому же значению в контексте. Это может привести к неожиданному перезаписыванию данных или к тому, что один пакет прочитает значение, которое установил другой.
Пустая структура решает это просто. Когда определяется type userContextKey struct{} в одном пакете и type userContextKey struct{} в другом, это два абсолютно разных типа с точки зрения компилятора. Они не конфликтуют, даже если имеют одинаковое имя, потому что существуют в разных пакетах.
🐸 Библиотека Go для собеса❓ Какие есть способы удаления элемента из среза
Удаление с сохранением порядка (O(n))
Используем
append для объединения частей слайса:
slice := []int{1, 2, 3, 4, 5}
newSlice := append(slice[:2], slice[3:]...) // [1, 2, 4, 5]
Быстрое удаление без сохранения порядка (O(1))
Меняем удаляемый элемент на последний:
slice := []int{10, 20, 30, 40, 50}
slice[1] = slice[4] // [10, 50, 30, 40, 50]
newSlice := slice[:4] // [10, 50, 30, 40]
Использовать, когда нужна максимальная производительность и порядок не важен
Удаление с краёв слайса
Для первого элемента:
newSlice := slice[1:]
Для последнего элемента:
newSlice := slice[:len(slice)-1]
🐸 Библиотека Go для собеса❓ Что такое сериализация и как она работает в Go
Когда программа хочет передать объект по сети или сохранить его на диск, она не может отправить его как есть, ей нужно превратить его в набор байт. Это и есть сериализация. Обратный процесс это десериализация — возвращение байты обратно в объект.
Чаще всего это нужно в веб-приложениях и распределённых системах, где данные постоянно путешествуют между сервисами.
Берём структуру и превращаем её в JSON:
type User struct {
Name string
Age int
}
user := User{Name: "Alice", Age: 30}
jsonBytes, _ := json.Marshal(user)
// {"Name":"Alice","Age":30}
Обратно из JSON в структуру:
var user User
json.Unmarshal(jsonBytes, &user)
🐸 Библиотека Go для собеса
اکنون در دسترس! پژوهش تلگرام ۲۰۲۵ — مهمترین بینشهای سال 
