Инструменты Go
Экосистема инструментов Go
Одно из достоинств Go — богатая стандартная экосистема. Многое встроено в go команду, остальное — де-факто стандарты сообщества.
gofmt: форматирование без споров
В большинстве команд разработчики тратят время на споры о форматировании: табы или пробелы, где ставить скобки. В Go этого нет — есть один стандарт и инструмент gofmt:
# Показать diff (не изменять файлы)
gofmt -d main.go
# Отформатировать файл
gofmt -w main.go
# Отформатировать весь проект
gofmt -w .goimports — улучшенный gofmt который ещё и управляет импортами:
go install golang.org/x/tools/cmd/goimports@latest
goimports -w .В IDE (VS Code + gopls, GoLand) форматирование применяется автоматически при сохранении файла. Настрой это с первого дня — код всегда будет выглядеть одинаково.
go vet: статический анализ
go vet ловит подозрительный код без запуска программы:
go vet ./...Что находит:
// Неверный формат printf
fmt.Printf("%d", "строка") // vet: arg "строка" has wrong type
// Копирование мьютекса (должен передаваться по указателю)
mu := sync.Mutex{}
mu2 := mu // vet: assignment copies lock value
// Unreachable code
func f() int {
return 1
fmt.Println("недостижимо") // vet: unreachable code
}
// Неверное использование atomic
var x int64
atomic.AddInt64(&x, 1)
y := x // vet: data race на x без atomicgo vet — обязательный шаг перед коммитом. Большинство CI конфигураций запускают его автоматически.
golangci-lint: всё сразу
golangci-lint запускает 50+ линтеров параллельно — быстро и удобно:
# Установка
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Запуск
golangci-lint run ./...Конфигурация .golangci.yml:
linters:
enable:
- govet # встроенный go vet
- errcheck # проверяет что ошибки не игнорируются
- staticcheck # мощный статический анализ
- gosimple # упрощения кода
- ineffassign # присваивания которые никогда не используются
- unused # неиспользуемый код
- gofmt # форматирование
- goimports # импорты
- misspell # опечатки в комментариях
- revive # замена golint
linters-settings:
errcheck:
check-blank: true # даже _ = riskyFunc()
issues:
max-same-issues: 3Запускай в CI на каждый pull request — это стандарт в Go-проектах.
staticcheck: умный анализатор
staticcheck — один из лучших статических анализаторов для Go:
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck ./...Что находит сверх go vet:
// Устаревшие API
ioutil.ReadFile(...) // SA1019: ioutil.ReadFile is deprecated, use os.ReadFile
// Бесполезные операции
strings.Replace(s, "a", "b", 0) // SA4009: n=0 означает "не заменять"
// Неправильное использование sync
var wg sync.WaitGroup
wg.Add(1)
go func() { wg.Done() }()
wg.Wait()
wg.Add(1) // SA2001: после Wait() — возможная гонка
// Неиспользуемые параметры функции
func process(ctx context.Context, data []byte) {
// ctx не используется вообще
return process2(data)
}go doc: документация в терминале
Go генерирует документацию из комментариев. Соглашение: комментарий начинается с имени того что документирует:
// User представляет пользователя системы.
// Используй NewUser для создания валидного экземпляра.
type User struct {
ID int
Email string
}
// NewUser создаёт нового пользователя с валидацией email.
// Возвращает ошибку если email невалиден.
func NewUser(email string) (*User, error) {
// ...
}# Документация пакета
go doc ./user
# Конкретная функция
go doc ./user NewUser
# Стандартная библиотека
go doc fmt.Println
go doc net/http.Client
# Локальный сервер документации
go install golang.org/x/tools/cmd/godoc@latest
godoc -http=:6060
# открой http://localhost:6060pprof: профилировщик
Когда программа работает медленно или ест много памяти — pprof:
import (
"net/http"
_ "net/http/pprof" // blank import регистрирует эндпоинты
)
func main() {
go http.ListenAndServe(":6060", nil)
// ...основной код
}# CPU профиль (30 секунд)
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# Heap профиль
go tool pprof http://localhost:6060/debug/pprof/heap
# Горутины
go tool pprof http://localhost:6060/debug/pprof/goroutine
# Интерактивный режим:
(pprof) top10 # топ функций по CPU/памяти
(pprof) list funcName # построчно
(pprof) web # граф вызовов в браузереДля тестов встроен бенчмарк-профайлер:
go test -bench=. -cpuprofile=cpu.out -memprofile=mem.out
go tool pprof cpu.outgo generate: кодогенерация
go generate запускает команды указанные в комментариях к коду:
// В файле models.go:
//go:generate stringer -type=Direction
type Direction int
const (
North Direction = iota
South
East
West
)go generate ./...
# Запустит: stringer -type=Direction
# Создаст: direction_string.go с методом String()Популярные кодогенераторы:
stringer— методы String() для enum-подобных типовmockgen— моки для интерфейсовprotoc-gen-go— код из protobuf схемsqlc— типобезопасный код из SQL запросов
Минимальный CI для Go проекта
# .github/workflows/go.yml
name: Go
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Vet
run: go vet ./...
- name: Test
run: go test -race -cover ./...
- name: Lint
uses: golangci/golangci-lint-action@v4-race включает детектор гонок — обязателен в CI. Находит data race которые иначе проявятся только в продакшне.
gofmt форматирует Go код по единому стандарту. Никаких споров о стиле — один стандарт для всей экосистемы.
package main
import "fmt"
func add(a int,b int)int{
return a+b
}
func main(){
x:=add(1,2)
fmt.Println(x)
}package main
import "fmt"
func add(a int,b int)int{
return a+b
}
func main(){
x:=add(1,2)
fmt.Println(x)
}