Menu

Printf и Sprintf в Golang: шпаргалка по глаголам формата fmt

Как пакет fmt в Go печатает и форматирует значения: Println, Printf, Sprintf и Errorf, полная таблица глаголов формата (%v, %+v, %d, %s, %q, %f, %T, %w и другие), ширина, точность и выравнивание.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

В пакете fmt три семейства функций печати, и в каждом одни и те же три варианта:

ФункцияКуда идёт выводФормат
Print, Println, Printfстандартный выводпо умолчанию, по умолчанию с пробелами и переводом строки, строка формата
Sprint, Sprintln, Sprintfвозвращаемая stringте же три стиля
Fprint, Fprintln, Fprintfлюбой io.Writer (файл, буфер, HTTP-ответ)те же три стиля
Errorfвозвращаемая errorстрока формата плюс %w для оборачивания

Println ставит пробелы между операндами и перевод строки в конце. Printf ничего не добавляет: \n вы пишете сами. Print ставит пробелы только между операндами, которые оба не строки; это настолько неожиданно, что в большинстве кода используют Println или Printf.

Глаголы формата

Общие

ГлаголЧто печатаетПример вывода
%vзначение в формате по умолчанию{Ana 31 [admin]}
%+vструктуры с именами полей{Name:Ana Age:31 Tags:[admin]}
%#vзначение в синтаксисе Gomain.User{Name:"Ana", Age:31, Tags:[]string{"admin"}}
%Tтипmain.User
%%знак процента%

%+v лучше всего подходит для отладки. Указатель на структуру печатается как &{...}, а не как адрес. Мапы печатаются с отсортированными ключами, поэтому вывод стабилен, хотя порядок обхода мапы случайный.

Целые числа

ГлаголЗначениеfmt.Sprintf(verb, 255)
%dдесятичное255
%bдвоичное11111111
%oвосьмеричное377
%Oвосьмеричное с префиксом 0o0o377
%x / %Xшестнадцатеричное, строчные или заглавныеff / FF
%#xшестнадцатеричное с префиксом 0x0xff
%cсимвол с этой кодовой точкойÿ
%qсимвольный литерал в кавычках'ÿ'
%Uформат UnicodeU+00FF

Числа с плавающей точкой

ГлаголЗначениеfmt.Sprintf(verb, 1234.5678)
%fдесятичная запись, по умолчанию 6 знаков1234.567800
%.2fдесятичная запись, 2 знака1234.57
%eэкспоненциальная запись1.234568e+03
%g%e или %f, что короче, без хвостовых нулей1234.5678
%vто же, что %g1234.5678

%.2f округляет точное двоичное значение float, поэтому fmt.Sprintf("%.2f", 2.675) даёт 2.67: ближайший к 2.675 float64 чуть меньше этого числа. Никогда не форматируйте деньги из float; храните копейки в целом числе.

Строки и байты

ГлаголЗначениеfmt.Sprintf(verb, "go\n")
%sстрока как естьgo и перевод строки
%qв двойных кавычках, escape-последовательности видны"go\n"
%xhex каждого байта676f0a
% xhex через пробел67 6f 0a

%s для []byte печатает его как текст; %v печатает числа ([104 105]).

Другие типы

ГлаголТипЧто печатает
%tbooltrue или false
%pуказатель, слайс, мапа, канал, функцияадрес, например 0xc000012345
%werror (только в Errorf)сообщение ошибки, и оборачивает её

Ширина, точность и выравнивание

Между % и глаголом можно поставить флаги, ширину и точность:

ФормаЭффект
%5dширина 5, выравнивание вправо (слева дополняется пробелами)
%-5dширина 5, выравнивание влево
%05dдополнение нулями
%.2f2 цифры после десятичной точки
%8.2fширина 8 и 2 знака после точки
%.3sне больше 3 символов строки
%+dвсегда показывать знак
%*dширина берётся из следующего аргумента

Заметьте: %.0f для 2.5 печатает 2, здесь Go округляет половину к чётному. Для строк ширина считается в рунах, а не в экранных колонках, поэтому иероглифы и эмодзи всё равно могут сбить выравнивание таблицы. Для ровных колонок с текстом переменной длины измерения за вас сделает text/tabwriter.

Индексы аргументов

%[n] выбирает аргумент по позиции, что позволяет использовать его повторно:

fmt.Printf("%[2]s %[1]s\n", "world", "hello") // hello world
fmt.Printf("%d %[1]x %[1]b\n", 10)             // 10 a 1010

Errorf и %w

fmt.Errorf создаёт error из строки формата. С %w она ещё и оборачивает другую ошибку, чтобы вызывающий код мог распознать исходную:

Используйте %w, когда вызывающему коду может понадобиться проверить причину, и %v, когда вы намеренно её скрываете. Начиная с Go 1.20 один вызов Errorf может содержать несколько глаголов %w. Оборачивание подробно разобрано на странице об обработке ошибок.

Свой формат через String()

Любой тип с методом String() string сам определяет, как его показывают %v, %s и Println:

%d обходит String() и печатает базовое число. Для типов ошибок аналогичный метод Error() string, и он имеет приоритет над String().

Если глагол неверный

fmt никогда не паникует из-за неправильного формата. Он печатает проблему прямо в выводе:

fmt.Printf("%d\n", "oops")
fmt.Printf("%d %d\n", 1)
fmt.Printf("%d\n", 1, 2)
%!d(string=oops)
1 %!d(MISSING)
1
%!(EXTRA int=2)

Такой вывод часто доезжает до продакшена, потому что ничего не падает. go vet ловит все три случая при сборке:

./main.go:8:2: fmt.Printf format %d has arg "oops" of wrong type string
./main.go:9:2: fmt.Printf format %d reads arg #2, but call has 1 arg
./main.go:10:2: fmt.Printf call needs 1 arg but has 2 args

Заметки о производительности

fmt принимает каждый аргумент как any и проверяет его тип во время выполнения (для структур, слайсов и мап используя рефлексию). Для логов и вывода это нормально, но в плотных циклах заметно. Чтобы преобразовать одно число, strconv.Itoa и strconv.FormatFloat быстрее, чем Sprintf. Чтобы собрать длинную строку в цикле, пишите в strings.Builder через fmt.Fprintf(&b, ...), а не склеивайте результаты Sprintf.

Часто задаваемые вопросы

Чем отличаются Println, Printf и Sprintf в Go?

fmt.Println печатает аргументы через пробел и добавляет перевод строки в конце. fmt.Printf печатает по строке формата и перевод строки не добавляет. fmt.Sprintf форматирует так же, как Printf, но возвращает результат строкой, а не печатает. fmt.Errorf делает то же самое и возвращает error.

Как вывести структуру с именами полей в Go?

Используйте %+v: fmt.Printf("%+v\n", user) печатает {Name:Ana Age:31}. %v печатает только значения, {Ana 31}, а %#v выводит синтаксис Go вместе с типом, main.User{Name:"Ana", Age:31}.

Как вывести float с двумя знаками после запятой в Go?

Используйте %.2f: fmt.Sprintf("%.2f", 3.14159) возвращает "3.14". Добавьте ширину для выравнивания колонок, %8.2f, или минус для выравнивания влево, %-8.2f. strconv.FormatFloat(f, 'f', 2, 64) даёт тот же результат без строки формата.

Что делает %w в fmt.Errorf?

%w форматирует ошибку как %v и заодно оборачивает её, так что новая ошибка несёт в себе исходную. Тогда errors.Is и errors.As могут найти обёрнутую ошибку: после err := fmt.Errorf("load config: %w", os.ErrNotExist) выражение errors.Is(err, os.ErrNotExist) истинно. %w работает только в fmt.Errorf.

Почему в выводе появляется %!d(string=...)?

Глагол не соответствует типу аргумента, например %d получил строку. fmt не паникует, а печатает проблему прямо в выводе: %!d(string=oops). Недостающие аргументы печатаются как %!d(MISSING), лишние как %!(EXTRA int=2). go vet ловит все три случая ещё до запуска программы.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ