Лекция 1. Знакомство с Go¶
Что такое Go и зачем он нужен¶
Go (или Golang — так часто пишут, чтобы было удобнее гуглить) — язык программирования, который разработали в Google три инженера: Роберт Гризмер, Роб Пайк и Кен Томпсон. Работа началась в 2007 году, публичный анонс был в ноябре 2009-го, а версия 1.0 вышла в марте 2012-го. Один из авторов — Кен Томпсон — это тот самый Томпсон, который вместе с Деннисом Ритчи стоял у истоков Unix и языка B (предка C). Роб Пайк — соавтор UTF-8 и операционной системы Plan 9. То есть Go придумали люди, которые буквально написали половину того, на чём держится современная вычислительная техника.
Мотивация была простой: внутри Google к концу нулевых сборка проекта на C++ занимала десятки минут, иерархия классов разрослась, а конкурентность через потоки операционной системы плохо масштабировалась. Хотелось язык, который:
- быстро компилируется (секунды, а не минуты);
- просто читается (минимум синтаксиса);
- имеет встроенную конкурентность (горутины и каналы);
- производит один статически слинкованный бинарник (легко деплоить — никакого «у меня на машине работает»);
- строго типизирован, но с короткими аннотациями.
В итоге Go получился намеренно «маленьким» языком: 25 ключевых слов (для сравнения, в Python около 35, а в C++ — больше 90). Нет наследования классов, нет дженериков долгое время не было (появились только в Go 1.18 в 2022 году), нет исключений в привычном смысле, нет тернарного оператора. Зато есть прямолинейная композиция через структуры, интерфейсы с «утиной» типизацией, и горутины — лёгкие потоки, которых на одной машине можно запустить миллионы.
Сегодня на Go написаны: Docker, Kubernetes, Terraform, Prometheus, Grafana, etcd, CockroachDB, Vault, большая часть инфраструктуры Cloudflare и Dropbox. Если вы будете работать в DevOps или платформенной разработке — Go встретится почти гарантированно.
Установка¶
macOS¶
Через Homebrew:
Или скачать .pkg с go.dev/dl.
Linux¶
Самый надёжный способ — скачать архив с официального сайта и распаковать в /usr/local:
wget https://go.dev/dl/go1.23.0.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.23.0.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
Пакеты из репозиториев дистрибутивов часто отстают на несколько минорных версий — для учебных целей сойдёт, но для работы лучше ставить вручную или через g (аналог nvm для Go).
Windows¶
Скачать .msi с go.dev/dl и запустить. После установки PATH прописывается автоматически.
Проверка¶
GOPATH, модули и где жить коду¶
Исторически Go требовал, чтобы весь код жил в одной директории $GOPATH/src/<полный-путь-репозитория> — например, ~/go/src/github.com/jtprogru/myproject. Это была боль: невозможно держать проект где удобно, версии зависимостей не фиксировались.
С версии Go 1.11 (2018 г.) появились модули (go mod), а с Go 1.16 они стали поведением по умолчанию. Теперь любой проект может лежать где угодно — главное, чтобы в корне был файл go.mod.
После этого появится файл go.mod:
Путь github.com/jtprogru/hello — это имя модуля. По нему другие проекты будут импортировать ваш код. Если вы не собираетесь публиковать модуль, имя может быть любым (например, просто hello), но префикс с доменом — общепринятая практика.
Первая программа¶
Создайте файл main.go:
Запуск:
Сборка в бинарник:
Размер бинарника — около 2 МБ для пустой программы (это вместе с рантаймом и сборщиком мусора). Внутри нет внешних зависимостей: его можно скопировать на голую Linux-машину без установленного Go и запустить.
Что значит каждая строка¶
package main— пакет с именемmainозначает «исполняемая программа», а не библиотека. Каждый Go-файл обязан начинаться сpackage <name>.import "fmt"— подключаем пакетfmtиз стандартной библиотеки (форматированный ввод-вывод).func main()— точка входа. Принимает 0 аргументов, ничего не возвращает.fmt.Println(...)— выводит аргументы через пробел и добавляет\nв конце.
Структура проекта¶
Простой проект:
Большой проект с несколькими пакетами:
myapp/
├── go.mod
├── go.sum
├── cmd/
│ └── server/
│ └── main.go # точка входа (package main)
├── internal/ # пакеты, которые нельзя импортировать извне модуля
│ ├── handler/
│ │ └── handler.go
│ └── storage/
│ └── postgres.go
├── pkg/ # пакеты, доступные внешним проектам (опционально)
│ └── client/
│ └── client.go
└── README.md
Стандарта де-юре для структуры проекта в Go нет, но соглашения уровня golang-standards/project-layout фактически прижились в индустрии. Особенно важна директория internal/ — это синтаксическая фича компилятора: пакеты внутри internal/ могут импортировать только модули того же дерева, что и сам internal/. Удобно, чтобы внутренняя реализация не утекала наружу.
Команды Go-инструмента¶
Утилита go — это «швейцарский нож»: компилятор, форматировщик, тест-раннер, менеджер зависимостей и линтер в одной обёртке.
| Команда | Что делает |
|---|---|
go run file.go |
Скомпилировать и сразу запустить (бинарник во временной директории, удаляется после выполнения). |
go build |
Скомпилировать в бинарник в текущей директории. По умолчанию имя бинарника = имени директории. |
go install |
Скомпилировать и положить бинарник в $GOPATH/bin (обычно ~/go/bin). |
go test ./... |
Запустить все тесты во всех пакетах модуля (./... — рекурсивный wildcard). |
go fmt ./... |
Отформатировать код по канону. Запускайте перед каждым коммитом (или настройте on-save в IDE). |
go vet ./... |
Статический анализ: подозрительные конструкции (например, неиспользуемый результат). |
go mod tidy |
Привести go.mod и go.sum в порядок: удалить неиспользуемые зависимости, добавить недостающие. |
go get <pkg> |
Добавить или обновить зависимость. |
go doc <pkg> |
Документация по пакету в терминале (например, go doc fmt.Println). |
Форматирование: gofmt и goimports¶
В Go нет холиваров про tabs vs spaces, нет двух школ расстановки скобок. Есть один официальный форматтер — gofmt — и одно правильное оформление. Запуск:
gofmt использует табы для отступов и переформатирует код по строгим правилам. На практике обычно используют чуть более продвинутую утилиту goimports — она делает то же самое, плюс автоматически добавляет/удаляет импорты:
Любая IDE с поддержкой Go умеет запускать goimports на сохранение — настройте это сразу.
Линтер: golangci-lint¶
go vet ловит только очевидные ошибки. Для серьёзной статической проверки используют golangci-lint — мета-линтер, который запускает десятки отдельных линтеров (errcheck, gosec, staticcheck, revive, ineffassign и др.):
brew install golangci-lint
# или
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
golangci-lint run ./...
Конфигурируется через .golangci.yml в корне проекта. В индустрии это де-факто стандарт — добавляйте сразу в CI.
VS Code для Go¶
В лекции 1 темы 7 уже описывали установку VS Code. Для Go нужны:
- Официальное расширение Go от команды Google (
golang.go). - После установки расширения VS Code предложит «Install/Update Tools» — соглашайтесь, оно поставит
gopls(language server),dlv(отладчик),goimports,staticcheckи др. - Включите в
settings.json:
{
"go.useLanguageServer": true,
"go.formatTool": "goimports",
"go.lintTool": "golangci-lint",
"go.lintOnSave": "package",
"[go]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
}
}
После этого редактор сам форматирует код, расставляет импорты, подсвечивает ошибки и предлагает рефакторинги.
Параллель с Python¶
| Python | Go |
|---|---|
python script.py |
go run main.go |
pip install requests |
go get github.com/some/package |
pyproject.toml + uv.lock |
go.mod + go.sum |
| виртуальное окружение | модуль (go mod init) — изоляции на уровне FS нет, версии зависимостей в go.mod |
if __name__ == "__main__": |
func main() в package main |
| интерпретатор + байт-код | компиляция в нативный бинарник |
black, ruff format |
gofmt, goimports |
ruff check, mypy |
go vet, golangci-lint |
pytest |
go test ./... |
Что почитать¶
- The Go Programming Language Specification — спецификация языка, читается за вечер;
- A Tour of Go — интерактивный туториал на 1–2 часа;
- Effective Go — каноническое описание идиом;
- Go by Example — короткие примеры на все основные темы;
- книга Алана Донована и Брайана Кернигана «The Go Programming Language» (есть русский перевод).
Итог¶
Go — намеренно простой, быстро компилируемый, статически типизированный язык с встроенной конкурентностью. Один бинарник, один форматтер, один официальный способ управления зависимостями (go mod). В следующей лекции — переменные, типы и управляющие конструкции.