fa
Feedback
Библиотека Go для собеса | вопросы с собеседований

Библиотека 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 для собеса