Оглавление
- История и философия языка
- Go Runtime и сборка мусора (GC)
- Настройка окружения и CLI
- Типы данных и переменные
- Управляющие конструкции
- Коллекции: Массивы и Слайсы
- Коллекции: Maps (Хеш-таблицы)
- Функции
- Структуры, Методы и Указатели
- Интерфейсы
- Обработка ошибок
- Экосистема, HTTP и организация проекта
1. История и философия языка
- Происхождение: Разработан в Google (Роберт Гризмер, Кен Томпсон, Роб Пайк). Выпущен в Open Source в 2009 году.
- Цели создания:
- Ускорение сборки и разработки крупных проектов.
- Упрощение управления зависимостями.
- Повышение читаемости кода.
- Создание удобных инструментов для конкурентного программирования.
- Ключевые принципы:
- Минимализм: Простой синтаксис, отсутствие лишних конструкций.
- Единообразие: Стандарт форматирования
gofmtзакреплен на уровне языка. - Быстрая компиляция: Пакетная система позволяет компилировать код параллельно.
- Явное лучше неявного: Отсутствие неявных преобразований типов и скрытых исключений.
2. Go Runtime и сборка мусора (GC)
Go Runtime — это код, исполняемый в фоне вместе с приложением. Он отвечает за инициализацию памяти, планировщик горутин и работу GC.
Сборщик мусора (GC)
- Алгоритм: Трассирующий конкурентный сборщик мусора на основе Concurrent Mark and Sweep (пометка и очистка).
- Фазы работы:
- Mark Setup (STW): Короткая пауза для включения барьера записи.
- Concurrent Mark: Поиск “живых” объектов параллельно с работой кода.
- Mark Termination (STW): Завершение пометки.
- Concurrent Sweep: Освобождение памяти от “мертвых” объектов.
- Особенности:
- Цель по STW-паузам — менее 1 мс.
- Барьеры записи (Write Barriers): Позволяют GC отслеживать изменения ссылок во время работы приложения.
- Настройка GOGC: Переменная определяет частоту запуска (дефолт
100— запуск при удвоении кучи).
3. Настройка окружения и CLI
Переменные окружения
GOPATH: Устаревшее рабочее пространство, сейчас используется для кеша модулей и бинарных файлов.GO111MODULE: Режим работы с модулями (по умолчаниюon).GOPROXY: Прокси для скачивания зависимостей.GOPRIVATE: Список репозиториев, которые не нужно проверять через публичные прокси.
Основные команды CLI
go mod init <name>: Инициализация нового модуля.go mod tidy: Синхронизация зависимостей (удаляет лишние, скачивает нужные).go run <file>: Компиляция и мгновенный запуск.go build: Сборка исполняемого бинарного файла.go env: Просмотр настроек окружения.
4. Типы данных и переменные
Примитивные типы
- Нулевые значения (Zero Values):
int,float,byte,rune:0bool:falsestring:""pointer,slice,map,chan,interface,func:nil
- Числовые типы: Строго разграничены (нельзя сложить
int32иint64без явного приведения). - Преобразование типов: Всегда явное —
int64(myInt32).
Строки, байты и руны
- String: Неизменяемая последовательность байт. Длина
len()возвращает количество байт, а не символов. - Byte: Алиас для
uint8. - Rune: Алиас для
int32, представляет один символ Unicode. - Итерация:
for i := range strидет по байтам,for i, r := range strидет по рунам.
Константы и iota
const: Значения вычисляются на этапе компиляции.iota: Целочисленный итератор внутри блокаconst. Сбрасывается в 0 в начале блока и увеличивается на 1 в каждой строке.
5. Управляющие конструкции
- if-else: Поддерживает короткое объявление переменной в условии:
if err := call(); err != nil { ... }. Область видимости переменной ограничена блокомif-else. - for: Единственный вид цикла в Go.
- Классический:
for i := 0; i < 10; i++. - Условный (как while):
for condition { }. - Бесконечный:
for { }. - Range:
for k, v := range collection.
- Классический:
- switch-case:
- Неявный break: Выполнение не проваливается в следующий
caseавтоматически. fallthrough: Ключевое слово для явного проваливания в следующий блок (без проверки условия).
- Неявный break: Выполнение не проваливается в следующий
6. Коллекции: Массивы и Слайсы
Массивы
- Фиксированная длина: Размер — часть типа (
[5]intи[10]int— разные типы). - Передача: Всегда копируются по значению.
Слайсы
- Структура: Слайс — это дескриптор, содержащий:
- Pointer: Указатель на базовый массив.
- Len: Текущая длина.
- Cap: Емкость (размер базового массива).
- Динамика: При превышении
cap,appendсоздает новый массив (обычно удвоенного размера) и копирует данные. - Копирование: Присваивание слайса (
s2 := s1) копирует только дескриптор. Оба слайса будут указывать на один базовый массив (Shallow Copy). - Slicing: Выражение
s[low:high]создает слайс, разделяющий память с оригиналом.
7. Коллекции: Maps (Хеш-таблицы)
- Структура hmap: Заголовок содержит
count,B(логарифм кол-ва бакетов),hashseedи указатель наbuckets. - Бакеты (bmap): Каждый бакет хранит до 8 пар ключ-значение. Внутри бакета сначала идут
tophash(8 старших бит хэша), затем 8 ключей, затем 8 значений. - Особенности:
- Небезопасны для конкурентного использования.
- Случайный порядок обхода: Go специально рандомизирует итерацию.
- Load Factor: При достижении средней нагрузки в 6.5 элементов на бакет начинается эвакуация (рост карты в 2 раза). Эвакуация происходит постепенно.
- Указатели: Нельзя взять адрес элемента карты (
&m[k]), так как при росте карты элементы перемещаются в памяти.
8. Функции
Основы и Variadic-функции
- Множественный возврат: Стандартный паттерн —
(value, error). - Variadic (
...T): Принимает любое количество аргументов, внутри функции они доступны как слайс.
Анонимные функции и замыкания
- Функции — “first class citizens”: их можно передавать, возвращать и присваивать.
- Замыкание (Closure): Анонимная функция, “захватывающая” переменные из своего лексического окружения.
Инициализация глобальных переменных с вызовом функций
- В Go глобальные (package-level) переменные инициализируются до вызова
main(). - Если переменная определяется через немедленно вызываемую функцию (IIFE — Immediately Invoked Function Expression), то эта функция выполнится при старте программы:
var a = func() int {
fmt.Println("5") // выполнится сразу при старте
defer func() {
fmt.Println("2") // выполнится после return
}()
return 0
}()
Порядок выполнения:
- Инициализация переменной
a:- Создаётся анонимная функция.
- Немедленно вызывается
().
- Выполняется
fmt.Println("5"). - Регистрируется
defer. - Возвращается значение
0. - Выполняется
defer, выводящий2.
Вывод программы при старте:
5
2
Важные моменты:
- Такой код выполняется до main(), даже если
main()пустой. - Если убрать
()после функции, она не будет вызвана при старте, а станет обычной анонимной функцией, которую можно вызвать позже:
var a = func() int {
fmt.Println("5")
return 0
} // без ()
Оператор defer
- Откладывает выполнение функции до момента выхода из текущей функции.
- LIFO: Выполняются в обратном порядке объявления.
- Аргументы: Вычисляются в момент объявления
defer, а не в момент выполнения.
9. Структуры, Методы и Указатели
Указатели
- Хранят адрес в памяти. Нулевое значение —
nil. - Разыменование
nil-указателя вызывает панику. - Операторы:
&(взятие адреса),*(разыменование).
Структуры и встраивание
- Видимость: Поля с большой буквы — публичные, с маленькой — приватные.
- Встраивание (Embedding): Позволяет встроить структуру без имени поля, “продвигая” её методы и поля на верхний уровень (замена наследованию).
Методы и ресиверы
- Value Receiver (
func (s T) Method()): Работает с копией. Не может изменить состояние оригинала. - Pointer Receiver (
func (s *T) Method()): Работает с оригиналом через указатель. Позволяет менять поля структуры. - Соглашение: Все методы одного типа должны иметь либо только value, либо только pointer ресиверы.
10. Интерфейсы
- Неявная реализация: Тип реализует интерфейс, если у него есть все методы интерфейса (без ключевых слов вроде
implements). - Empty Interface (
any): Удовлетворяет любому типу. - Правило: “Принимайте интерфейсы, возвращайте структуры”.
- Интерфейс под капотом — это пара
(type, value). Еслиvalue == nil, ноtype != nil, сам интерфейс не равенnil.
11. Обработка ошибок
- error — это интерфейс с методом
Error() string. - Идиома: Проверка ошибки сразу после вызова —
if err != nil { return err }. - Wrapping: Оборачивание ошибки с помощью
fmt.Errorf("...: %w", err). - Проверка:
errors.Is(err, target): Проверка на равенство конкретной ошибке в цепочке.errors.As(err, &target): Проверка на принадлежность типу в цепочке.
12. Экосистема, HTTP и организация проекта
- Проект:
/cmd: Точки входа (main.go)./internal: Приватный код проекта./pkg: Публичные библиотеки (использовать осторожно).
- HTTP:
- Клиент: Нужно всегда закрывать тело ответа
res.Body.Close(). - Middleware: Оборачивание
http.Handlerдля добавления логики (логи, авторизация).
- Клиент: Нужно всегда закрывать тело ответа
- Context: Стандартный способ управления таймаутами, отменой задач и передачи метаданных (trace ID). Передается первым аргументом.