Форматирование строк в Go — руководство и шпаргалка
Важно: форматные глаголы чувствительны к регистру. Неправильный глагол может привести к неожиданному выводу.
Введение
При разработке на Go форматирование строк встречается часто: печать логов, генерация сообщений, преобразование типов в человекочитаемый вид или подготовка данных для вывода. Go использует знакомую модель printf: строка формата + значения. Понимание глаголов и функций fmt важно для корректного и предсказуемого вывода.
Определение: форматный глагол — символ или набор символов, начинающийся с %, который указывает, как представлять соответствующее значение.
Основные функции пакетa fmt
- Printf(format string, a …interface{}) — форматирует и выводит в stdout; возвращает количество записанных байт и ошибку.
- Sprintf(format string, a …interface{}) string — возвращает отформатированную строку.
- Fprintf(w io.Writer, format string, a …interface{}) (n int, err error) — пишет отформатированную строку в writer.
- Fscanf(r io.Reader, format string, a …interface{}) (n int, err error) — парсит данные из reader по формату.
Примеры из исходного кода (сохранены без изменений):
fmt.Println("This is a test %v", 90)
fmt.Printf("This is a test %v", 90) Объяснение: Println не интерпретирует форматные глаголы — он просто выведет все аргументы; Printf и Sprintf интерпретируют строку формата.
fmt.Printf("This is a test %v", 90) var result = fmt.Sprintf("This is a test %v", 90) // write data to standard output
result, err = fmt.Fprintf(writer, "This is a test %v", 90)var take string
// read data from the given string
readString := strings.NewReader("This is a test")
read, err := fmt.Fscanf(reader, "%v", &take)
Базовые глаголы и как их читать
Ниже — компактная и точная шпаргалка по наиболее употребимым глаголам fmt. Эти описания соответствуют поведению пакета fmt и подходят для типичных задач.
Общие глаголы:
| Глагол | Описание |
|---|---|
| %v | Значение в «умолчательном» формате. |
| %+v | Для структур — показывает имена полей и значения. |
| %#v | Представление в Go-синтаксисе (идет через компилятор-представление). |
| %T | Тип значения. |
| %% | Вывод символа % (без значения). |
Пример со структурой (сохранён оригинальный пример):
type any struct {
name string
age int
isLoggedIn bool
}
var instance = any {
name: "John Doe",
age: 34,
isLoggedIn: true,
}
var result = fmt.Sprintf("This is a struct formatting example %+v", instance)
fmt.Println(result)
Ожидаемый вывод:
This is a struct formatting example {name:John Doe age:34 isLoggedIn:true}Специальные глаголы для базовых типов
Целые числа и символы:
| Глагол | Описание |
|---|---|
| %b | Двоичный формат (base 2). |
| %c | Символ, соответствующий коду Unicode. |
| %d | Десятичный формат (base 10). |
| %o | Восьмеричный формат (base 8). |
| %x | Шестнадцатеричный с a-f. |
| %X | Шестнадцатеричный с A-F. |
| %U | Юникод-формат: U+1234 (эквивалент “U+%04X”). |
Пример (сохранён оригинал):
var result = fmt.Sprintf("This is an integer formatting example %d", 90)
fmt.Println(result)Вещественные числа:
| Глагол | Описание |
|---|---|
| %b | Без десятичной точки; научная запись с экспонентой степени два (см. strconv.FormatFloat с ‘b’). |
| %e | Научная нотация с e, например -1.234456e+78. |
| %E | То же, но с E вместо e. |
| %f | Десятичная точка, без экспоненты, например 123.456. |
| %F | Синоним %f. |
| %g | %e для больших экспонент, %f иначе; выбирает компактный вид. |
| %G | %E для больших экспонент, %F иначе. |
| %x | Шестнадцатеричная форма с экспонентой степени два (для float). |
| %X | Верхний регистр для шестнадцатеричной формы (для float). |
Пример (сохранён оригинал):
var result = fmt.Sprintf("This is a floating point example %f", 432.9503)
fmt.Println(result)
Строки и срезы байт:
| Глагол | Описание |
|---|---|
| %s | Неперемодифицированные байты строки или среза. |
| %q | Двойная кавычка, строка безопасно экранирована. |
| %x | Шестнадцатеричное представление, 2 символа на байт, нижний регистр. |
| %X | То же, но верхний регистр. |
Пример (сохранён оригинал):
var score = "example"
var result = fmt.Sprintf("This is a string formatting example %s", score)
fmt.Println(result)Глагол %p — печатает указатели в шестнадцатеричном формате. Например, fmt.Printf(“%p”, &x).
Форматные флаги, ширина и точность
Синтаксис форматирования может расширяться: %[индекс] [флаги][ширина][.точность][gлагол]. Примеры:
- %6d — ширина 6, выравнивание вправо для числа.
- %-6s — ширина 6, выравнивание влево для строки.
- %.2f — две цифры после запятой для float.
- %06d — заполнить нулями слева до ширины 6.
Правила:
- Ширина и точность можно задавать как аргументы: %.f, width и precision передаются в список значений.
- Индексация аргументов: %[2]d — взять второй аргумент.
Практические рекомендации и лучшие практики
- Для логов используйте fmt.Sprintf для формирования строки, а затем логируйте. Это упрощает тесты и международализацию.
- Для многократной сборки строки используйте strings.Builder — это эффективнее, чем частые Sprintf.
- Если вам нужна шаблонная генерация (HTML, электронные письма), рассмотрите text/template или html/template для безопасности вставок.
- Всегда указывайте точность для float при необходимости детерминированного вывода.
Совет: если не уверены в типе — используйте %v или %T для отладки.
Когда форматирование может подвести (примеры ошибок)
- Неверный глагол по типу значения. Пример: попытка распечатать срез байт как %d приведёт к неправильному выводу.
- Неправильная последовательность аргументов при индексированной подстановке — вы получите неожиданные значения.
- Использование Println вместо Printf при наличии форматных глаголов — глаголы останутся в строке.
- Форматирование в цикле без буфера: снижает производительность и создаёт много аллокаций.
Пример ошибки:
fmt.Printf("Value: %d", "not an int") // runtime: неправильный типАльтернативы и когда их выбирать
- strings.Builder — для постепенного накопления строки при сложной конкатенации.
- text/template / html/template — при необходимости шаблонной подстановки с безопасной экранизацией (HTML).
- encoding/json — если нужен машинно-читаемый формат (JSON) вместо человекочитаемого.
- log package — для форматированных логов с уровнями, префиксами и выводом времени.
Ментальные модели и эвристики
- «Printf — это для файловых/спец-выводов; Sprintf — для формирования строки; Fprintf — для записи в любой writer.»
- «%v для отладки, конкретный глагол для конечной публикации».
- «Выбирай минимальный достаточный глагол — он проще, надёжнее и понятнее для читателя кода.»
Шпаргалка (quick cheat sheet)
- %v — универсальный, отладочный.
- %+v — структура с именами полей.
- %#v — Go-литерал.
- %T — тип.
- %s, %q — строки.
- %d, %b, %o, %x — целые.
- %f, %e, %g — float.
- %p — указатель.
Мини-примеры:
fmt.Printf("Count: %d\n", 12)
fmt.Printf("Hex: %#x\n", 255)
fmt.Printf("User: %+v\n", user)
fmt.Printf("Type: %T\n", user.Age)Ролевые чек-листы
Разработчик:
- Выбрать %v для отладки.
- Указать точность для float там, где важна точность.
- Не использовать Println с глаголами.
Код-ревьюер:
- Проверить соответствие глаголов типам аргументов.
- Проверить, не создаёт ли формат лишние аллокации внутри цикла.
- Убедиться, что нельзя инъецировать необработанные данные в формат (для шаблонов — использовать template).
Опер или поддержка:
- Убедиться, что логи читаемы и содержат минимально необходимую информацию.
- Проверить количество форматируемых полей в ключевых логах (чтобы парсинг логов не ломался).
Критерии приёмки
- Все основные виды данных форматируются с ожидаемым выводом (строки, числа, структуры).
- Логи содержат требуемые поля в указанном формате.
- Тесты на форматирование (если есть) проходят для различных наборов данных.
Минимальные тесты:
- Сравнить Sprintf с ожидаемой строкой для примера.
- Проверить, что %v выводит приемлемый результат для сложного типа.
Технический чек-лист для миграции/рефакторинга
- Замена конкатенации на Sprintf: проанализировать влияние на аллокации.
- Замена Printf на логгер: убедиться, что формат и уровни сохраняются.
- При переводе на template проверить экранирование.
Примеры и сценарии
Форматирование детерминированного float для CSV:
value := 3.1415926535 line := fmt.Sprintf("%.3f,%.2f", value, value) // line == "3.142,3.14"Генерация отладочного вывода структуры:
fmt.Printf("user=%+v\n", user)Запись отформатированной строки в файл:
file, _ := os.Create("out.txt") defer file.Close() fmt.Fprintf(file, "Result: %d\n", result)
Контраргументы и ограничения метода
- Printf/ Sprintf хороши для человекочитаемого вывода, но не заменяют сериализацию для API.
- Форматирование чувствительно к локали: fmt не форматирует числа с локализованными разделителями (для этого нужны внешние библиотеки).
- Для высокой производительности при большом количестве конкатенаций strings.Builder предпочтительнее.
Краткое руководство по отладке форматов
- Используйте %T, чтобы убедиться в типе аргумента.
- Временно выводите %+v или %#v для структур, чтобы увидеть содержимое.
- Если видите неожиданные значения — проверьте порядок аргументов и индексы.
Резюме
Форматирование строк в Go реализовано через пакет fmt и мощную систему форматных глаголов. Понимание основных глаголов (%v, %d, %s, %f, %q, %p и т.д.), флагов ширины и точности, а также знание альтернатив (strings.Builder, template, log) помогут писать корректный и эффективный код.
Ключевые выводы:
- Используйте Sprintf для сборки строк, Printf для вывода и Fprintf для записи в writer.
- %v — удобен для отладки; конкретные глаголы — для окончательного вывода.
- Следите за производительностью при форматировании в горячих путях.
Краткое резюме и ресурсы
- Изучите таблицу глаголов и запомните базовые.
- Используйте шаблоны для сложного форматирования и экранирования.
- Для логов и сериализации применяйте подходящие библиотеки.
Дополнительные материалы: официальная документация пакета fmt (в Go standard library) и документация по strings.Builder и text/template.
Похожие материалы
Запись нескольких USB‑миков в GarageBand
Будильник Android не срабатывает — что делать
Загрузка файлов в Firebase Storage из React
Локальная учётная запись в Windows 8.1 — как перейти