Гид по технологиям

Форматирование кода Go: пакет `format` и команда `go fmt`

6 min read Go Обновлено 06 Dec 2025
Форматирование кода Go — format и go fmt
Форматирование кода Go — format и go fmt

Частичный вид ноутбука вблизи и чашка кофе с логотипом Go.

Форматирование кода — важная практика для повышения читаемости, консистентности и повторного использования. В экосистеме Go есть чёткие правила форматирования, и инструментальная поддержка позволяет автоматически привести код к этим правилам.

О чём эта статья

  • Что такое пакет format и команда go fmt.
  • Как использовать go fmt в командной строке и из CI.
  • Как форматировать исходники из программы с помощью go/format и Config.
  • Когда автоматическое форматирование не подходит и альтернативы.
  • Практические чеклисты для разработчика и ревьюера, краткий справочник и критерии приёмки.

Пакет format и команда go fmt

Пакет go/format реализует стандартное форматирование исходного кода Go. Команда go fmt (alias для gofmt) применяет те же правила форматирования из командной строки и обычно используется в локальной разработке и CI.

Чтобы просмотреть помощь по команде fmt, выполните:

go help fmt

Чтобы форматировать файл вручную:

go fmt main.go

В действительности go fmt вызывает gofmt с флагами, эквивалентными следующей команде:

gofmt -l -w
  • -l — выводит имена изменённых файлов.
  • -w — перезаписывает файлы с применённым форматированием.

Флаг -x показывает команды, которые будут выполнены:

go fmt -x main.go

Флаг -n показывает, какие команды были бы выполнены, не внося изменений:

go fmt -n main.go

Простой пример программы

Ниже — упрощённый пример программы, которую можно отформатировать с помощью go fmt.

package main

import (
    "fmt"
)

func main() {
    var x int = 5
    for i := 0; i < x; i++ {
        fmt.Println("Hello World!")
    }
}

Форматирование исходников из программы: format.Source

Если нужно форматировать код программно (например, в редакторе, генераторе кода или инструменте), используйте функцию format.Source. Она принимает срез байт с исходным кодом и возвращает отформатированный срез байт.

Пример чтения файла, форматирования и записи обратно:

package main

import (
    "io/ioutil"
    "log"
    "go/format"
)

func main() {
    fileContent, err := ioutil.ReadFile("main.go")
    if err != nil {
        log.Fatalln("Ошибка чтения файла:", err)
    }

    formatted, err := format.Source(fileContent)
    if err != nil {
        log.Fatalln("Ошибка форматирования:", err)
    }

    if err := ioutil.WriteFile("main.go", formatted, 0644); err != nil {
        log.Fatalln("Ошибка записи файла:", err)
    }
}

Важно: в современных версиях Go рекомендуют использовать os.ReadFile/os.WriteFile вместо ioutil (ioutil частично устарел), но приведённый код остаётся рабочим и часто встречается в существующих проектах.

Форматирование кода, переданного в память

Можно отформатировать строку или срез байт с кодом без работы с файлами:

package main

import (
    "fmt"
    "go/format"
    "log"
)

func main() {
    src := `package main

import (
    "fmt"
    "math"
)

func main() {
    var a float64 = 3
    var b float64 = 4
    var c float64 = 5
    var s float64 = (a + b + c) / 2
    var area float64 = math.Sqrt(s * (s-a) * (s-b) * (s-c))
    fmt.Println("The area of the triangle is:", area)
}
`

    formatted, err := format.Source([]byte(src))
    if err != nil {
        log.Fatalln("Ошибка форматирования:", err)
    }

    fmt.Println(string(formatted))
}

После форматирования обычно нужно преобразовать срез байт в строку: string(formatted).

Результат операции форматирования: пример отформатированного кода Go.

Настройка форматирования с помощью Config

Пакет go/format предоставляет тип Config, который позволяет настроить поведение форматтера перед применением к данным. Пример создания конфигурации:

import "go/format"

config := &format.Config{
    Tabwidth: 8,
    UseTabs: false,
    TabIndent: true,
    NoFinalTab: true,
    Spaces: true,
    NoTrimTrailingSpace: false,
}

Когда вы используете config.Source, это применит выбранные опции к переданному срезу байт:

formatted, err := config.Source(fileContent)
if err != nil {
    log.Fatalln("Ошибка форматирования с Config:", err)
}

Параметры позволяют контролировать ширину таба, замену табов пробелами, удаление финальных табуляций и т.д. Используйте эти параметры, если у вас есть специфические требования к форматированию в рамках генераторов кода или внутренних инструментов.

Что форматирование делает и чего не делает

Важно понимать границы автоматического форматирования:

  • Форматирование касается пробелов, табуляций, пробелов вокруг операторов, отступов и выравнивания. Оно не изменяет логику программы.
  • Форматирование не исправляет синтаксические ошибки. Если исходный код содержит ошибки парсинга, format.Source вернёт ошибку.
  • Форматирование не заменяет линтер: go fmt не выявляет потенциальные баги, не даёт советов по стилю именования и архитектуре.

Когда форматирование не подходит (контрпример)

  • Генераторы кода, которые намеренно выравнивают колонки в табличном виде и полагаются на специфическое «вручную» выровненное представление; после go fmt такое выравнивание будет утрачено.
  • Фрагменты кода в документации (README), где формат важен для визуального восприятия, но который не должен быть изменён автоматически.
  • Если вы используете нестандартный стиль (очень редкий случай), автоматическое форматирование может противоречить вашим правилам.

Альтернативные подходы

  • Использовать gofmt с разными флагами напрямую (gofmt имеет дополнительные опции).
  • Для проверки стиля в CI: запускать go fmt -l и падать при наличии изменённых файлов.
  • Применять go vet, staticcheck и linters для выявления проблем, которые go fmt не покрывает.

Модель принятия решения (хитрости и эвристики)

  • Всегда применять go fmt при сохранении файла в редакторе (IDE-плагины делают это автоматически).
  • На этапе коммита: добавьте хуки pre-commit, которые запускают go fmt и отменяют коммит при изменениях.
  • В CI: запускайте go fmt -l; если есть непокрытые файлы — фейлить сборку.
flowchart TD
    A[Изменён файл .go] --> B{Форматирование нужно?}
    B -- Да --> C[Запустить go fmt]
    C --> D{gofmt вернул изменения?}
    D -- Да --> E[Ошибка в CI / отмена коммита]
    D -- Нет --> F[Продолжить]
    B -- Нет --> F

Чеклисты по ролям

Разработчик:

  • Запустил go fmt локально или настроил автоформат при сохранении.
  • Прогнал тесты после форматирования.
  • Проверил, что git diff содержит только форматирование, а не непреднамерённые изменения логики.

Ревьюер:

  • Игнорировать изменения, которые касаются только форматирования (если они отдельным коммитом).
  • Потребовать отвязки функциональных изменений от форматирования (разные коммиты).
  • В CI требовать, чтобы все файлы были отформатированы автоматически.

Инженер DevOps:

  • Добавить шаг в pipeline: go fmt -l ./… и падать при ненулевом выводе.
  • Обеспечить, чтобы посткоммитные хуки на CI не меняли содержимое репозитория незаметно для разработчика без уведомления.

Шпаргалка команд

  • Просмотр помощи: go help fmt
  • Локальное форматирование файла: go fmt main.go
  • Форматирование всех пакетов: go fmt ./…
  • Показать, какие файлы изменятся: gofmt -l -w
  • Имитировать изменения: go fmt -n
  • Показать команды: go fmt -x

Критерии приёмки

  • Все изменённые файлы проходят проверку go fmt в CI (go fmt -l ./… не выводит файлов).
  • Коммиты разделяют форматирование и функциональные изменения.
  • Комментарии и документация не содержат неотформатированные блоки кода, если они исполняемые — обеспечить отдельную проверку.

Короткий справочник терминов

  • go fmt /gofmt — инструмент форматирования Go-кода.
  • format.Source — функция пакета go/format для форматирования исходного кода в памяти.
  • Config — структура в go/format для настройки поведения форматтера.

Советы по внедрению в команду

  • Настройте редакторы (VS Code, GoLand и т. п.) на автоформат при сохранении.
  • Внедрите pre-commit hook (например, с использованием pre-commit или husky), который запускает go fmt.
  • В CI включите проверку: go fmt -l ./… и блокируйте PR, если список файлов не пуст.

Риски и способы их снижения

  • Риск: массовое форматирование затруднит ревью большого PR.
    • Смягчение: разбивайте коммиты — первый коммит только с форматированием, последующие с логикой.
  • Риск: форматирование нарушит выровненные таблицы в сгенерированных файлах.
    • Смягчение: добавьте правила для генераторов кода, чтобы они форматировали выходной код после генерации.

Итог

Автоматическое форматирование — быстрый выигрыш для качества кода и скорости ревью. Внедрите go fmt в рабочий процесс: локально в редакторе, как pre-commit hook и как проверку в CI. Используйте пакет go/format и Config для форматирования из кода, когда нужны кастомные инструменты или генераторы.

Важно: форматирование не заменяет статический анализ и код-ревью — это инструмент для согласованности представления кода, а не для поиска логических ошибок.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство