Уроки модуля (1/5)
Расширенный `fmt`
Пакет fmt — это шлюз для всего текстового ввода-вывода в Go. Хорошо это знать — значит писать читаемые журналы, выявлять информативные ошибки и идиоматически форматировать значения, не прибегая к внешним библиотекам.
Четыре семьи
fmt предоставляет функции четырех семейств, различающихся префиксом:
Print*→ записывает вos.Stdout(Print,Println,Printf).Fprint*→ записывает в любойio.Writer(Fprintln(os.Stderr, ...),Fprintf(file, ...)).Sprint*→ возвращает строку без печати (Sprintf,Sprintln).Errorf→ создает отформатированныйerror.
fmt.Println("hello") // stdout
fmt.Fprintln(os.Stderr, "boom") // stderr
s := fmt.Sprintf("[%d]", 42) // "[42]"
err := fmt.Errorf("parse %q: %w", in, base) // wrapped errorРазница между Print и Println заключается только в пробеле между аргументами и завершающей новой строкой: Println всегда добавляет \n, Print нет, Printf соответствует формату.
Основные глаголы
| Глагол | Что он делает |
|---|---|
%v | Значение по умолчанию (вызывает String(), если реализовано). |
%+v | Структура с именами полей. |
%#v | Синтаксис Go (полезен для отладки и создания снимков). |
%T | Динамический тип значения. |
%d | Целое число по основанию 10. |
%b %o %x %X | Двоичный, восьмеричный, шестнадцатеричный (строчные/прописные). |
%f %e %g | Плавающая точка: фиксированная, экспоненциальная, компактная. |
%s | Строка (или error/Stringer). |
%q | Строка в стиле Go в кавычках (включая escape-символы). |
%c | Символ Юникода (rune). |
%p | Указатель в шестнадцатеричном формате. |
%w | Перенос ошибок (только внутри Errorf). |
type Point struct{ X, Y int }
p := Point{1, 2}
fmt.Printf("%v\n", p) // {1 2}
fmt.Printf("%+v\n", p) // {X:1 Y:2}
fmt.Printf("%#v\n", p) // main.Point{X:1, Y:2}
fmt.Printf("%T\n", p) // main.PointШирина, точность, флаги
Числовые и строковые команды принимают ширину и точность:
%6d→ минимальная ширина 6, левое дополнение пробелами.%-6d→ ширина 6, отступ справа (флаг-).%06d→ ширина 6, дополнение0(флаг0).%.2f→ точность до 2 десятичных цифр.%8.2f→ ширина 8, точность 2.
fmt.Printf("|%6d|\n", 42) // | 42|
fmt.Printf("|%-6d|\n", 42) // |42 |
fmt.Printf("|%06d|\n", 42) // |000042|
fmt.Printf("|%8.2f|\n", 3.14)// | 3.14|Для выровненных таблиц фиксированная ширина + %-...s для текстовых столбцов является самым простым шаблоном перед переходом на text/tabwriter.
%w и перенос ошибок
%w особенный: он работает только внутри fmt.Errorf и сохраняет исходную ошибку в цепочке, так что errors.Is и errors.As могут пройти по ней.
if _, err := os.Open(path); err != nil {
return fmt.Errorf("read config %q: %w", path, err)
}Использование %v вместо %w печатает сообщение об ошибке, но разрывает цепочку: нет развертывания, нет errors.Is. Правило: если вы хотите, чтобы вызывающий абонент мог различить тип или идентификатор ошибки, используйте %w (только один на каждый Errorf).
Упражнения
Используйте fmt.Sprintf, чтобы отформатировать строку «[42]» из целого числа 42, а затем распечатать ее.
Решение доступно после 3 попыток
Выведите структуру p с глаголом %+v (она должна включать имена полей).
Решение доступно после 3 попыток
Какой глагол, используемый в fmt.Errorf, сохраняет цепочку ошибок для ошибок.Is/As?
err := fmt.Errorf("read %q: ???", path, base)