Разное / продвинутое

37 вопросов

Продвинутые темы Go: go vet, go fmt, go:embed, сборщик мусора, рефлексия, unsafe.Pointer, variadic функции, замыкания и другие особенности языка.

1 Что делает go fmt? 🟢 Лёгкий
Ответ: B) Форматирует код по стандартам Go

go fmt (или gofmt) автоматически форматирует код: отступы табами, расстановка скобок, выравнивание. Единый стиль для всех Go-проектов.

Подробнее →
2 Можно ли в Go вернуть несколько значений из функции? 🟢 Лёгкий
Ответ: B) Да

Go поддерживает множественные возвращаемые значения: func div(a, b int) (int, error). Это основа обработки ошибок в Go. Можно использовать именованные возвращаемые значения.

Подробнее →
3 Как преобразовать []byte в string? 🟢 Лёгкий
Ответ: B) string(b)

string(b) - преобразование []byte в string. Создаёт копию данных (строки иммутабельны). Обратно: []byte(s). Эти преобразования - O(n) по памяти из-за копирования.

Подробнее →
4 Почему для множества (set) в Go используют map[K]struct{} вместо map[K]bool? 🟢 Лёгкий
Ответ: A) struct{} занимает 0 байт памяти, а bool - 1 байт на каждый элемент; при большом количестве ключей разница существенна

struct{} - пустая структура, занимает 0 байт. В map[string]struct{} значения не потребляют память. При миллионах ключей экономия заметна.

Подробнее →
5 Что делает go vet? 🟡 Средний
Ответ: B) Находит подозрительные конструкции в коде

go vet - статический анализатор. Находит ошибки, которые компилятор пропускает: неправильные аргументы Printf, копирование мьютексов, недостижимый код, ошибки в тегах структур.

Подробнее →
6 Что такое //go:embed? 🟡 Средний
Ответ: B) Директива для встраивания файлов в бинарник

//go:embed (Go 1.16+) встраивает содержимое файлов в переменные при компиляции. Можно встроить строку, []byte или embed.FS. Удобно для шаблонов, статики, конфигов.

Подробнее →
7 Какой сборщик мусора используется в Go? 🟡 Средний
Ответ: B) Concurrent mark-and-sweep

Go использует конкурентный трёхцветный mark-and-sweep GC. Он работает параллельно с программой, обеспечивая паузы < 1 мс. Не generational (как в Java).

Подробнее →
8 Что делает runtime.NumGoroutine()? 🟡 Средний
Ответ: B) Возвращает текущее число горутин

runtime.NumGoroutine() возвращает количество активных горутин. Полезно для мониторинга и обнаружения утечек горутин. Если число постоянно растёт - у вас утечка.

Подробнее →
9 Что такое reflect пакет? 🟡 Средний
Ответ: B) Позволяет исследовать типы и значения во время выполнения

reflect - рефлексия: можно узнать тип переменной, её поля, вызывать методы динамически. Используется в encoding/json, ORM. Медленнее прямого доступа - используйте только когда необходимо.

Подробнее →
10 В чём разница между make и new? 🟡 Средний
Ответ: B) make - для slice/map/chan, new - возвращает указатель

make(T, args) - создаёт и инициализирует slice, map или chan (возвращает сам тип). new(T) - выделяет память и возвращает *T с zero value. Разные задачи.

Подробнее →
11 Что такое stringer interface? 🟡 Средний
Ответ: B) Тип с методом String() string

Интерфейс fmt.Stringer содержит метод String() string. Типы, реализующие его, автоматически используются fmt.Println для красивого вывода. Аналог toString() в Java.

Подробнее →
12 Какая функция запускается первой в Go-программе? 🟡 Средний
Ответ: C) init() затем main()

Порядок: 1) инициализация зависимых пакетов (их init()), 2) init() пакета main, 3) main(). Все init() завершаются до начала main().

Подробнее →
13 Что такое variadic function? 🟡 Средний
Ответ: B) Функция с переменным числом аргументов (func f(a ...int))

...T в параметре означает, что функция принимает 0+ аргументов типа T. Внутри функции это слайс []T. Примеры: fmt.Println(a ...any), append(s []T, elems ...T). Должен быть последним параметром.

Подробнее →
14 Что выведет: defer fmt.Println("a"); defer fmt.Println("b")? 🟡 Средний
Ответ: B) b a

Defer'ы выполняются в порядке LIFO (стек). Сначала зарегистрирован "a", затем "b". При выходе сначала выполняется последний ("b"), потом первый ("a").

Подробнее →
15 Как передать слайс в variadic-функцию? 🟡 Средний
Ответ: B) f(slice...)

Оператор ... после слайса "разворачивает" его в отдельные аргументы. f([]int{1,2,3}...) эквивалентно f(1, 2, 3). Без ... весь слайс будет одним аргументом - ошибка типов.

Подробнее →
16 Что такое замыкание (closure)? 🟡 Средний
Ответ: B) Функция, захватывающая переменные из внешней области

Замыкание - анонимная функция, которая "замыкает" (захватывает) переменные из окружающей области видимости. Переменные разделяются по ссылке, а не копируются. Частая ловушка: замыкание в цикле.

Подробнее →
17 Что делает go generate? 🟡 Средний
Ответ: B) Запускает команды из комментариев //go:generate

go generate ищет комментарии //go:generate command в исходниках и выполняет указанные команды. Используется для кодогенерации: stringer, mockgen, protobuf. Не запускается автоматически при go build.

Подробнее →
18 Что выведет: s := "hello"; fmt.Println(s[0])? 🟡 Средний
Ответ: B) 104 (код байта)

Индексация строки возвращает byte, не символ. s[0] - байт с кодом 104 (ASCII-код 'h'). fmt.Println выводит числовое значение байта. Для символа: string(s[0]) или fmt.Printf("%c", s[0]).

Подробнее →
19 Что такое sync.Map? 🟡 Средний
Ответ: B) Потокобезопасная map

sync.Map - конкурентно-безопасная map, не требующая внешней блокировки. Оптимизирована для случаев, когда ключи стабильны (много чтений, мало записей).

Подробнее →
20 Что такое go:build тег? 🟡 Средний
Ответ: B) Условие компиляции файла

//go:build linux - директива условной компиляции. Файл будет включён только при сборке для Linux. Можно комбинировать: //go:build linux && amd64. Заменил старый формат // +build.

Подробнее →
21 Что вернёт fmt.Sprintf("%T", 42)? 🟡 Средний
Ответ: B) "int"

Глагол %T выводит тип значения. 42 - нетипизированная константа, по умолчанию int. %T полезен для отладки. Работает с любыми типами, включая кастомные.

Подробнее →
22 Какой пакет для атомарных операций? 🟡 Средний
Ответ: B) sync/atomic

sync/atomic предоставляет атомарные операции: AddInt64, LoadInt64, StoreInt64, CompareAndSwapInt64. Работают без мьютексов, на уровне процессорных инструкций. Быстрее мьютексов для простых счётчиков.

Подробнее →
23 Что такое method set типа? 🟡 Средний
Ответ: B) Набор методов, определённых для типа

Method set определяет, какие интерфейсы тип реализует. У значения T - только value receiver методы. У указателя *T - и value, и pointer receiver методы. Поэтому *T может реализовать интерфейс, который T не реализует.

Подробнее →
24 Что вернёт cmp.Or("", "", "default") (Go 1.22+)? 🟡 Средний
Ответ: B) "default"

cmp.Or возвращает первое ненулевое значение из аргументов. Для строк zero value - пустая строка, для чисел - 0. Аналог оператора || для значений по умолчанию в JavaScript. cmp.Or("", "", "default") = "default".

Подробнее →
25 Как правильно реализовать graceful shutdown HTTP-сервера в Go? 🟡 Средний
Ответ: C) Перехват сигнала (SIGTERM) + server.Shutdown(ctx)

Graceful shutdown: 1) перехватить OS-сигнал через signal.NotifyContext; 2) вызвать server.Shutdown(ctx) - перестаёт принимать новые, дожидает текущие; 3) ctx с таймаутом ограничивает ожидание. server.Close() прерывает все соединения немедленно.

Подробнее →
26 Что делает пакет golang.org/x/sync/errgroup? 🟡 Средний
Ответ: B) Управляет группой горутин с отменой при первой ошибке

errgroup.Group запускает горутины (g.Go), ждёт завершения (g.Wait) и возвращает первую ошибку. С errgroup.WithContext при первой ошибке отменяется context. Замена WaitGroup + ручного сбора ошибок. Стандартный инструмент для параллельных задач.

Подробнее →
27 Что произойдет при вызове метода с pointer receiver на nil-указателе? 🟡 Средний
Ответ: B) Метод вызовется; паника произойдет только при обращении к полям через nil-указатель внутри метода

Go позволяет вызывать методы на nil-указателе. Метод получит nil как receiver. Паника будет только при попытке разыменовать nil внутри метода (обращение к полям).

Подробнее →
28 Как вызвать бесконечную рекурсию через fmt.Stringer? 🟡 Средний
Ответ: A) Вызвать fmt.Sprintf("%s", s) внутри метода String(), потому что fmt снова вызовет String() для форматирования

Если String() вызывает fmt.Sprintf("%s", s) или fmt.Sprint(s), fmt обнаружит Stringer и снова вызовет String(). Результат - бесконечная рекурсия и stack overflow.

Подробнее →
29 Скомпилируется ли: func Log(args ...any) {}; names := []string{"a","b"}; Log(names...)? 🟡 Средний
Ответ: B) Нет: []string нельзя передать как ...any; нужен явный []any или передача поэлементно

[]string и []any - разные типы в Go. Нельзя развернуть []string в ...any через names... Нужно явно скопировать в []any или передать names как один аргумент: Log(names).

Подробнее →
30 Сколько байт занимает заголовок slice, string и interface на 64-bit платформе? 🟡 Средний
Ответ: B) slice = 24 (pointer + len + cap), string = 16 (pointer + len), interface = 16 (type + data pointer)

slice header: указатель на массив + len + cap = 3x8 = 24 байт. string header: указатель + len = 2x8 = 16 байт. interface: указатель на тип + указатель на данные = 2x8 = 16 байт.

Подробнее →
31 Что такое unsafe.Pointer? 🔴 Сложный
Ответ: B) Указатель, обходящий систему типов

unsafe.Pointer - универсальный указатель, который можно привести к любому типу указателя. Обходит проверки типов. Используется для низкоуровневых оптимизаций. Нарушает гарантии безопасности Go.

Подробнее →
32 Что произойдёт при panic(nil)? 🔴 Сложный
Ответ: B) Программа завершится с panic

panic(nil) вызывает панику. Начиная с Go 1.21, panic(nil) оборачивается в *runtime.PanicNilError, чтобы recover() мог отличить "не было паники" от "panic(nil)".

Подробнее →
33 Для чего нужен sync.Pool? 🔴 Сложный
Ответ: B) Пул переиспользуемых объектов для снижения нагрузки на GC

sync.Pool кеширует аллоцированные объекты для повторного использования. Снижает давление на GC. Объекты могут быть удалены GC в любой момент - не для постоянного хранения.

Подробнее →
34 Скомпилируется ли: type MyInt int; var x MyInt = 5; var y int = 3; fmt.Println(x + y)? 🔴 Сложный
Ответ: B) Нет, нельзя складывать разные типы

type MyInt int создаёт новый тип. MyInt и int - разные типы, нельзя складывать без явного приведения: x + MyInt(y) или int(x) + y. При этом x + 3 работает, потому что 3 - нетипизированная константа.

Подробнее →
35 Где будет размещена переменная: func f() *int { x := 42; return &x }? 🔴 Сложный
Ответ: B) В куче (heap)

Escape analysis определяет, что &x переживёт функцию, и размещает x в куче. Без return &x переменная осталась бы на стеке. Проверить: go build -gcflags='-m'. Аллокации в куче дороже - объект обрабатывается GC.

Подробнее →
36 Для чего используется директива //go:linkname? 🔴 Сложный
Ответ: B) Доступ к неэкспортированным символам другого пакета

//go:linkname позволяет обращаться к неэкспортированным функциям и переменным других пакетов, обходя систему видимости Go. Используется в стандартной библиотеке, но не рекомендуется в пользовательском коде - это хрупкий хак без гарантий совместимости.

Подробнее →
37 Для чего используется переменная окружения GODEBUG? 🔴 Сложный
Ответ: B) Управляет поведением рантайма Go без перекомпиляции

GODEBUG управляет различными аспектами рантайма: GC (gctrace=1), сеть (netdns=go), HTTP (http2debug=1), TLS и другие. Это позволяет менять поведение программы без перекомпиляции. С Go 1.21 GODEBUG также используется для обратной совместимости.

Подробнее →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.