Библиотека Go для собеса | вопросы с собеседований
Открыть в Telegram
Вопросы с собеседований по Go и ответы на них. Учиться у нас: https://proglib.io/w/0b524a15 По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot Наши каналы: https://t.me/proglibrary/9197
Больше7 425
Подписчики
-524 часа
-77 дней
+630 день
Архив постов
11 сентября | 19:00
Офлайн в Москве | Онлайн
Кто выступит:
🔹Виталий Левченко, Engineering manager Wildberries проведет воркшоп на тему LLM для конкурентного Go кода;
🔹Владимир Марунин, Senior Developer Clatch, МТС Web Services расскажет про
эффективное использование sync.Map в Go;
🔹Роман Ерема, Developer MWS Cloud Platform поделится опытом разработки Cloud Controller Manager: интеграции Kubernetes с облаком MWS.
Для участия зарегистрируйся по ссылке.
До встречи на True Tech Go!
❓ Для чего нужен пакет cgo и что он собой представляет
Cgo создаёт мост между Go и C: код на Go вызывает функции C через пространство имён C, а код на C может вызывать экспортированные функции Go.
Cвойства cgo:
• Встраивание кода C в преамбуле перед
import "C".
• Доступ к именам из заголовков и преамбулы через пространство имён C.
• Преобразования типов выполняются явно при переходе из C.* к чистым типам Go и обратно.
• Память: объекты, выделенные в C, освобождаются C.free, длительное хранение указателей на Go-память в C запрещено.
package randc
/*
#include <stdlib.h>
*/
import "C"
func Random() int {
return int(C.random()) // C.long -> Go int
}
func Seed(i uint) {
C.srandom(C.uint(i)) // Go uint -> C unsigned int
}
Разбор примера:
• import "C" — псевдопакет: ссылка на пространство имён C.
• В rand четыре обращения к C: вызовы C.random и C.srandom, приведение C.uint(i) и сам импорт.
• Random вызывает random из libc. В C она возвращает long (C.long в cgo), результат приводится к Go int перед выдачей наружу.
• Seed принимает Go int, приводит к C.uint и передаёт в srandom.
• Комментарий непосредственно перед import "C" — преамбула. Она компилируется как C-заголовок для C-частей пакета: здесь можно объявлять/определять функции и переменные, затем использовать их из Go через C.*.
🐸 Библиотека Go для собесаТест для Golang-разработчиков, проверьте свои знания, готовы ли вы к обучению на курсе.
💻 Ответьте на 20 вопросов за 30 минут и проверьте, готовы ли вы к обучению на онлайн-курсе «Golang Developer. Professional» от OTUS. Сейчас Go становится все востребованнее, благодаря своей производительности, масштабируемости и экосистеме.
После 5 месяцев обучения вы сможете:
— Писать production-ready код, многопоточные и конкурентные программы.
— Понимать синтаксис и внутреннее устройство языка Go.
— Разворачивать микросервисы с помощью Docker.
— Проектировать и реализовывать микросервисную архитектуру на Go.
Также вас ждет прокачка навыков на реальных коммерческих кейсах и под руководством экспертов в этой области. Старт курса 30 июля, успейте на курс .Возможна рассрочка.
👉 ПРОЙТИ ТЕСТ
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
⚡️ Бесплатный вебинар — прогнозируем цены и не сходим с ума
21 августа в 19:00 МСК будет бесплатный вебинар с Марией Жаровой — экспертом в ML и Data Science.
Тема:
«Введение в машинное обучение: как спрогнозировать стоимость недвижимости».Подробности рассказываю в гс выше — включай, чтобы не пропустить.
❓ Как осуществить своп двух переменных без временной переменной
1️⃣ Сложение и вычитание (без временной переменной)
a := 5 b := 3 a = a + b // a становится 8 b = a - b // b становится 5 a = a - b // a становится 3
a и b меняются местами за три операции без использования временной переменной.
2️⃣ XOR (исключающее ИЛИ)
a := 5 // 0101 в двоичной системе b := 3 // 0011 в двоичной системе a = a ^ b // a становится 6 (0110) b = a ^ b // b становится 5 (0101) a = a ^ b // a становится 3 (0011)Двойное применение XOR с теми же операндами восстанавливает исходное значение, поэтому значения переставляются. 3️⃣ Простая функция со свопом
func main() {
fmt.Println(swap())
}
func swap() []int {
a, b := 15, 10
b, a = a, b
return []int{a, b}
}
swap меняет a и b местами и возвращает результат.
🐸 Библиотека Go для собеса🔥 Последняя неделя, чтобы забрать курс по AI-агентам по старой цене!
Пока вы тестируете Copilot, другие уже учатся строить AI-агентов, которые реально работают на бизнес. Хватит отставать!
Наш курс — это концентрат практики по LangChain и RAG. Улучшенная версия, доработанная по отзывам первого потока.
📆 Старт — 15 сентября.
💸 Цена 49 000 ₽ — только до 24 августа.
👉 Зафиксировать цену
❓ Опишите принцип работы стека и приведите реализацию на Go
Стек — тип данных, основанный на принципе LIFO (last in — first out, «последним пришёл — первым вышел»).
Элементы стека связаны линейно, каждый указывает на следующий, доступ к середине отсутствует.
Элемент, помещённый в стек последним, извлекается первым. После извлечения он удаляется, и верхним становится предыдущий.
Операции:
push — добавление элемента,
pop — удаление верхнего элемента,
peek — возврат верхнего элемента без удаления.
Реализация на Go через срез:
type Stack struct {
items []int
}
func (s *Stack) Push(item int) {
s.items = append(s.items, item)
}
func (s *Stack) Pop() int {
if len(s.items) == 0 {
panic("Stack is empty!")
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item
}
func (s *Stack) Peek() int {
if len(s.items) == 0 {
panic("Stack is empty!")
}
return s.items[len(s.items)-1]
}
func (s *Stack) IsEmpty() bool {
return len(s.items) == 0
}
func (s *Stack) Size() int {
return len(s.items)
}
Мы использовали срез для хранения элементов стека. Метод Push добавляет элемент на верх стека, метод Pop извлекает его, а метод Peek позволяет посмотреть верхний элемент без его извлечения. Также мы использовали проверку стека на наличие элементов.
🐸 Библиотека Go для собеса❓ Как проверить тип данных переменной в Go во время выполнения программы
Оператор
switch в Go позволяет проверять тип переменной во время выполнения. Каждый switch включает хотя бы один оператор case, который работает как условие, и блок default, который выполняется, если ни одно из условий не выполнено.
Пример, который проверяет, является ли значение интерфейса i типом int или string:
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Double %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}
Результат:
Double 21 is 42 "hello" is 5 bytes long I don't know type bool!🐸 Библиотека Go для собеса
❓ Как анонимные функции и замыкания используются в языке Go
• Анонимные функции в Go создаются внутри других функций. Это функции без имени, которые можно вызывать или передавать так же, как обычные функции.
• В Go есть возможность доступа к состоянию внешней функции из анонимных функций, даже после завершения внешней функции. Это позволяет создавать замыкания.
Замыкание — это функция, которая сохраняет доступ к переменным внешней функции после её завершения.
Пример с функцией
incrementer, которая создает анонимную функцию для увеличения значения переменной i:
func incrementer() func() int {
i := 0
return func() int {
i++
return i
}
}
При вызове incrementer создается новая копия переменной i, и возвращенная функция увеличивает её значение. Каждый последующий вызов incrementer создает свою копию переменной i.
func main() {
increment := incrementer()
fmt.Println(increment()) // 1
fmt.Println(increment()) // 2
fmt.Println(increment()) // 3
newIncrement := incrementer()
fmt.Println(newIncrement()) // 1
}
🐸 Библиотека Go для собеса❓ Для чего в Go применяется пустой идентификатор
Пустой идентификатор
_ в Go используется как анонимный заполнитель. Он позволяет обращаться к значению, но не связывает его с переменной.
1️⃣ Игнорирование возвращаемых значений функции: если функция возвращает несколько значений, но нужно только одно из них.
value, _ := someFunction()2️⃣Игнорирование элементов в
range: при переборе элементов среза или карты, когда нужен только ключ или только значение.
for k, _ := range myMap {
fmt.Println(k)
}
for _, v := range mySlice {
fmt.Println(v)
}
3️⃣Импорт пакета: если пакет нужно импортировать только для выполнения его инициализации, без использования его функций или типов.
import _ "image/png"4️⃣ Игнорирование переменных в множественном присваивании:
_, y := getCoordinates()5️⃣ Игнорирование ошибок: можно использовать для игнорирования ошибок, но это не рекомендуется.
result, _ := strconv.Atoi("123")
6️⃣ Использование в анонимных структурах: при создании анонимной структуры, когда не нужно имя для одного из полей.
person := struct {
Name string
_ int
}{"Alice", 30}
➡️ Пустой идентификатор полезен, но злоупотреблять им не следует, особенно для игнорирования ошибок.
🐸 Библиотека Go для собеса🔎 Ищете способы улучшить работу с данными в Go?
На открытом вебинаре разберемся, как использовать итераторы для работы с большими данными. Поймем, что изменилось с Go 1.23 и какие преимущества дают ленивые итераторы.
❗️ Изучите, как заменить стандартные циклы на более эффективные итераторы и оптимизировать свой код. Освойте лучшие практики разработки на Go!
Присоединяйтесь к открытому уроку 19 августа в 20:00 МСК: https://clc.to/M-aU0Q
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
❓ Что такое гонка данных и как она проявляется в языке Go
➡️ Гонки данных — это ошибки, возникающие в конкурентных системах, когда две горутины одновременно обращаются к одной и той же переменной, и хотя бы одно из обращений — запись. Для предотвращения таких ошибок в Go есть примитивы синхронизации.
➡️ Состояние гонки (Race Condition) описывает ситуацию, когда поведение программы зависит от порядка выполнения операций. Гонка данных — это тип состояния гонки.
Пример гонки данных, которая может привести к сбоям и повреждению памяти:
func main() {
c := make(chan bool)
m := make(map[string]string)
go func() {
m["1"] = "a" // Первый конфликтный доступ
c <- true
}()
m["2"] = "b" // Второй конфликтный доступ
<-c
for k, v := range m {
fmt.Println(k, v)
}
}
➡️ Для диагностики таких ошибок Go предоставляет встроенный детектор гонок данных. Для его использования достаточно добавить флаг -race при запуске команд:
$ go test -race mypkg
$ go run -race mysrc.go
$ go build -race mycmd
$ go install -race mypkg
➡️ Переменная окружения GORACE позволяет настроить параметры детектора гонок, например:
$ GORACE="log_path=/tmp/race/report Strip_path_prefix=/my/go/sources/" go test -race
🐸 Библиотека Go для собеса🚀 Главная ошибка новичка в ML — строить звездолёт вместо велосипеда
Многие сразу хотят свою Midjourney, но в итоге получают только выгорание.
Успех начинается с «велосипеда»: научитесь предсказывать цены или классифицировать отзывы. Освойте базу, а уже потом стройте «звездолёты».
Наш курс «ML для старта в Data Science» — это и есть тот самый правильный старт от простого к сложному.
👉 Начните правильно
Берёте курс «ML для старта» до конца недели — Python в подарок.
❗А 21 августа пройдет бесплатный вебинар с Марией Жаровой: узнаете, какие проекты качают скилл, а какие качают ваши нервы.
А какой самый сложный проект вы брались делать в самом начале? 🫢
❓ Что включает в себя набор примитивов синхронизации пакета sync в Go
Примитивы синхронизации — инструменты (в основном из пакета
sync), которые обеспечивают безопасную работу с общими данными и координацию горутин.
• sync.Mutex — базовый механизм взаимного исключения. Позволяет заблокировать доступ к ресурсу, чтобы только одна горутина могла его изменять в текущий момент.
• sync.RWMutex — вариант мьютекса с разделением на блокировку для чтения и записи:
Одновременно могут выполняться несколько операций чтения.
Запись возможна только при полном исключении доступа.
• sync.WaitGroup — позволяет дождаться завершения группы горутин. Удобен для синхронного старта/остановки процессов.
• sync.Once — гарантирует однократное выполнение кода, даже при множественных вызовах из разных горутин.
• sync.Cond — условная переменная, при помощи которой горутина может "заснуть" до наступления определённого события.
Go предлагает два подхода к синхронизации — через примитивы sync и через каналы. Первые дают низкоуровневый контроль, вторые — более декларативный способ координации.
🐸 Библиотека Go для собеса❓ Как минимизировать использование памяти в Go при работе с большими структурами данных
➡️ Избегайте глобальных переменных, они остаются в памяти на весь срок работы программы.
➡️ Выбирайте правильные типы данных используйте
int8, int16 вместо int, если диапазон позволяет.
➡️ Используйте sync.Pool для повторного использования часто создаваемых объектов.
➡️ Ленивая инициализация, инициализируйте данные только по мере необходимости.
➡️ Передавайте указатели на структуры, это экономит память по сравнению с копиями.
➡️ Срезы против массивов — используйте массивы, если размер данных известен заранее.
➡️ Освобождение ресурсов, присваивайте nil неиспользуемым структурам.
➡️ Используйте буферизацию, она снижает количество выделений памяти.
➡️ Оптимизируйте структуры, переупорядочив поля, можно снизить их размер.
🐸 Библиотека Go для собеса❓ Что собой представляет «затенение» переменной (shadowing) в Go
➖ В Go «затенение» (shadowing) происходит, когда переменная, объявленная в локальной области видимости, имеет такое же имя, как и переменная во внешней области видимости. Внутренняя переменная «затеняет» внешнюю, делая её недоступной.
package main
import (
"fmt"
)
func main() {
x := 10
if true {
x := 5 // затенение внешней переменной x
fmt.Println(x) // выводит 5
}
fmt.Println(x) // выводит 10
}
➖ «Затенение» может быть особенно запутывающим, когда оно касается переменных, полученных из результатов функций, таких как err. Пример часто встречающегося кода в Go:
value, err := someFunction()
if err != nil {
// обработка ошибки
}
// ...
value2, err := anotherFunction() // новое затенение переменной err
if err != nil {
// обработка ошибки
}
Если случайно использовать := вместо =, вы создадите новую переменную err, которая «затенит» переменную err из внешней области видимости. Это может привести к неправильной обработке ошибок, так как внешняя ошибка будет проигнорирована.
❕Обнаружение затенения:
1. go vet -shadow ./...
2. golangci-lint run --enable shadow
3. Использование инструмента shadow:
$ go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
$ go vet -vettool=$(which shadow)
🐸 Библиотека Go для собеса❓ Расскажите о механизме мьютексов в Go и укажите существующие типы
Mutex (mutual exclusion — взаимное исключение) — примитив синхронизации для защиты критической секции программы. Он предотвращает гонки данных и deadlock’и, обеспечивая эксклюзивный доступ к ресурсу.
Критическая секция — участок кода, где одновременно может работать только одна горутина.
➡️
sync.Mutex — эксклюзивная блокировка
Только одна горутина может захватить мьютекс и получить доступ к ресурсу.
var mu sync.Mutex
func increment() {
mu.Lock()
count++
mu.Unlock()
}
Здесь мы рассматриваем защиту глобальной переменной count при инкременте из множества горутин.
➡️ sync.RWMutex — концептуально то же самое, что и Mutex, но дает вам немного больше контроля над памятью.
Позволяет:
RLock — множеству горутин читать одновременно.
Lock — только одному писателю, без читателей.
var mu sync.RWMutex
func set(key, value string) {
mu.Lock()
cache[key] = value
mu.Unlock()
}
func get(key string) string {
mu.RLock()
defer mu.RUnlock()
return cache[key]
}
Дает безопасный доступ к кэшу — много читателей, один писатель.
🐸 Библиотека Go для собеса❓ Как Go реализует обработку ошибок, в отличие от других языков программирования
1️⃣ Явная обработка — в Go нет исключений.
Функции, которые могут завершиться с ошибкой, возвращают её как отдельное значение наряду с результатом.
2️⃣ Множественные возвращаемые значения — стандартный шаблон:
val, err := someFunction()
if err != nil {
// обработка ошибки
}
3️⃣ Кастомные ошибки — через пакет errors можно определять собственные типы ошибок и добавлять к ним полезную информацию.
4️⃣ Обогащение контекста — с Go 1.13 доступны errors.Is, errors.As и fmt.Errorf(... %w ...) для оборачивания ошибок с сохранением исходной причины.
func DoSomething() error {
if err := someOperation(); err != nil {
return fmt.Errorf("someOperation failed: %w", err)
}
return nil
}
5️⃣ Нет finally — очистка ресурсов выполняется через defer.
6️⃣ Panic и recover — используются только для критических непредвиденных ситуаций, например выхода за границы массива.
🐸 Библиотека Go для собеса❓ Чем является rune в Go и как он связан с символами Unicode
Работа со строками в Go не ограничивается ASCII-символами, в текстах часто встречаются символы других языков и эмодзи. Для корректной обработки таких символов используется тип
rune.
rune — это псевдоним для int32, предназначенный для хранения Unicode-кода одного символа.
При переборе строки с помощью конструкции for range, Go обходит строку по символам Unicode, автоматически преобразуя её в последовательность rune.
Примеры:
• Объявление и инициализация руны:
var r rune = 'A'
• Преобразование строки в срез рун:
s := "Привет"
runes := []rune(s)
• Итерация по рунам в строке:
for _, r := range "Привет" {
fmt.Printf("%c ", r)
}
// Вывод: П р и в е т
• Обратное преобразование среза рун в строку:
runes := []rune{'П', 'р', 'и', 'в', 'е', 'т'}
s := string(runes) // "Привет"
• Получение Unicode-кода руны:
r := 'A' code := int32(r) // 65• Проверка длины строки в рунах:
s := "Привет" length := utf8.RuneCountInString(s) // 6🐸 Библиотека Go для собеса
❓ Как создать простой веб-сервер на Go с использованием стандартной библиотеки
Базовый пример:
package main
import (
"fmt"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/hello", helloHandler)
http.ListenAndServe(":8080", nil)
}
1️⃣ Подключаем fmt для форматированного вывода и net/http для работы с HTTP.
2️⃣ Обработчик запросов: функция helloHandler отвечает на все запросы сообщением "Hello, World!".
3️⃣ С помощью http.HandleFunc регистрируем обработчик на корневой эндпоинт ("/hello").
4️⃣ http.ListenAndServe(":8080", nil) запускает сервер на порту 8080.
➡️ После запуска кода при переходе по адресу http://localhost:8080/hello вы получите ответ: "Hello, World!"
Также можно использовать http.FileServer:
package main
import "net/http"
func main() {
port := ":8080"
handler := http.FileServer(http.Dir("."))
http.ListenAndServe(port, handler)
}
Аналог python -m http.server — раздаёт текущую директорию по HTTP.
🐸 Библиотека Go для собеса
Уже доступно! Исследование Telegram 2025 — ключевые инсайты года 
