25 вопросов
Продвинутые темы Go: go vet, go fmt, go:embed, сборщик мусора, рефлексия, unsafe.Pointer, variadic функции, замыкания и другие особенности языка.
go vet? 🟡 Средний
▶
go vet - статический анализатор. Находит ошибки, которые компилятор пропускает: неправильные аргументы Printf, копирование мьютексов, недостижимый код, ошибки в тегах структур.
Подробнее →go fmt? 🟢 Лёгкий
▶
go fmt (или gofmt) автоматически форматирует код: отступы табами, расстановка скобок, выравнивание. Единый стиль для всех Go-проектов.
Подробнее →//go:embed? 🟡 Средний
▶
//go:embed (Go 1.16+) встраивает содержимое файлов в переменные при компиляции. Можно встроить строку, []byte или embed.FS. Удобно для шаблонов, статики, конфигов.
Подробнее →Go использует конкурентный трёхцветный mark-and-sweep GC. Он работает параллельно с программой, обеспечивая паузы < 1 мс. Не generational (как в Java).
Подробнее →runtime.NumGoroutine()? 🟡 Средний
▶
runtime.NumGoroutine() возвращает количество активных горутин. Полезно для мониторинга и обнаружения утечек горутин. Если число постоянно растёт - у вас утечка.
Подробнее →reflect пакет? 🟡 Средний
▶
reflect - рефлексия: можно узнать тип переменной, её поля, вызывать методы динамически. Используется в encoding/json, ORM. Медленнее прямого доступа - используйте только когда необходимо.
Подробнее →make и new? 🟡 Средний
▶
make(T, args) - создаёт и инициализирует slice, map или chan (возвращает сам тип). new(T) - выделяет память и возвращает *T с zero value. Разные задачи.
Подробнее →Интерфейс fmt.Stringer содержит метод String() string. Типы, реализующие его, автоматически используются fmt.Println для красивого вывода. Аналог toString() в Java.
Подробнее →Порядок: 1) инициализация зависимых пакетов (их init()), 2) init() пакета main, 3) main(). Все init() завершаются до начала main().
Подробнее →Go поддерживает множественные возвращаемые значения: func div(a, b int) (int, error). Это основа обработки ошибок в Go. Можно использовать именованные возвращаемые значения.
Подробнее →...T в параметре означает, что функция принимает 0+ аргументов типа T. Внутри функции это слайс []T. Примеры: fmt.Println(a ...any), append(s []T, elems ...T). Должен быть последним параметром.
Подробнее →defer fmt.Println("a"); defer fmt.Println("b")? 🟡 Средний
▶
Defer'ы выполняются в порядке LIFO (стек). Сначала зарегистрирован "a", затем "b". При выходе сначала выполняется последний ("b"), потом первый ("a").
Подробнее →Оператор ... после слайса «разворачивает» его в отдельные аргументы. f([]int{1,2,3}...) эквивалентно f(1, 2, 3). Без ... весь слайс будет одним аргументом - ошибка типов.
Подробнее →Замыкание - анонимная функция, которая «замыкает» (захватывает) переменные из окружающей области видимости. Переменные разделяются по ссылке, а не копируются. Частая ловушка: замыкание в цикле.
Подробнее →go generate? 🟡 Средний
▶
go generate ищет комментарии //go:generate command в исходниках и выполняет указанные команды. Используется для кодогенерации: stringer, mockgen, protobuf. Не запускается автоматически при go build.
Подробнее →unsafe.Pointer? 🔴 Сложный
▶
unsafe.Pointer - универсальный указатель, который можно привести к любому типу указателя. Обходит проверки типов. Используется для низкоуровневых оптимизаций. Нарушает гарантии безопасности Go.
Подробнее →s := "hello"; fmt.Println(s[0])? 🟡 Средний
▶
Индексация строки возвращает byte, не символ. s[0] - байт с кодом 104 (ASCII-код 'h'). fmt.Println выводит числовое значение байта. Для символа: string(s[0]) или fmt.Printf("%c", s[0]).
Подробнее →[]byte в string? 🟢 Лёгкий
▶
string(b) - преобразование []byte в string. Создаёт копию данных (строки иммутабельны). Обратно: []byte(s). Эти преобразования - O(n) по памяти из-за копирования.
Подробнее →panic(nil)? 🔴 Сложный
▶
panic(nil) вызывает панику. Начиная с Go 1.21, panic(nil) оборачивается в *runtime.PanicNilError, чтобы recover() мог отличить «не было паники» от «panic(nil)».
Подробнее →sync.Map? 🟡 Средний
▶
sync.Map - конкурентно-безопасная map, не требующая внешней блокировки. Оптимизирована для случаев, когда ключи стабильны (много чтений, мало записей).
Подробнее →sync.Pool? 🔴 Сложный
▶
sync.Pool кеширует аллоцированные объекты для повторного использования. Снижает давление на GC. Объекты могут быть удалены GC в любой момент - не для постоянного хранения.
Подробнее →go:build тег? 🟡 Средний
▶
//go:build linux - директива условной компиляции. Файл будет включён только при сборке для Linux. Можно комбинировать: //go:build linux && amd64. Заменил старый формат // +build.
Подробнее →fmt.Sprintf("%T", 42)? 🟡 Средний
▶
Глагол %T выводит тип значения. 42 - нетипизированная константа, по умолчанию int. %T полезен для отладки. Работает с любыми типами, включая кастомные.
Подробнее →sync/atomic предоставляет атомарные операции: AddInt64, LoadInt64, StoreInt64, CompareAndSwapInt64. Работают без мьютексов, на уровне процессорных инструкций. Быстрее мьютексов для простых счётчиков.
Подробнее →Method set определяет, какие интерфейсы тип реализует. У значения T - только value receiver методы. У указателя *T - и value, и pointer receiver методы. Поэтому *T может реализовать интерфейс, который T не реализует.
Подробнее →