深色模式
Go语言之 fmt 格式化
概述
fmt.Printf 看起来只是打印函数,但真正用久了就会发现,格式化输出其实在调试、日志、错误信息、文本拼接里都很常出现。问题通常不在“有没有占位符”,而在“这个值该用哪个动词输出才最合适”。
这篇文章不追求列全手册,而是把日常最常用、最容易混的格式化规则收拢起来。
最常用的格式化动词
| 动词 | 作用 |
|---|---|
%v | 默认格式输出值 |
%+v | 结构体时附带字段名 |
%#v | 按 Go 语法形式输出 |
%T | 输出值的类型 |
%d | 十进制整数 |
%f | 浮点数 |
%s | 字符串 |
%q | 带引号字符串 |
%t | 布尔值 |
%p | 指针地址 |
%% | 字面上的 % |
通用输出最常见的是 %v
go
fmt.Printf("%v\n", value)它适合快速查看值本身。
如果是结构体,%+v 往往更好用:
go
fmt.Printf("%+v\n", user)因为它会把字段名一起带出来。
而 %#v 更适合做调试,它会尽量按 Go 语法形式输出,方便看清具体类型结构。
%T 用来看类型
go
fmt.Printf("%T\n", value)排查接口值、泛型实例、反射输入时,这个动词很实用。很多“它到底是什么类型”的问题,用 %T 一下就能先定位大方向。
数字类型不要混着打
整数常见是:
go
fmt.Printf("%d\n", 123)
fmt.Printf("%x\n", 255)
fmt.Printf("%b\n", 5)浮点数常见是:
go
fmt.Printf("%f\n", 3.14)
fmt.Printf("%.2f\n", 3.14159)
fmt.Printf("%e\n", 3.14159)这里最容易错的不是格式记不住,而是把值类型和动词混用,最后输出异常或者得到 %! 这类提示。
字符串和字符也别混
字符串常见用法:
go
fmt.Printf("%s\n", "hello")
fmt.Printf("%q\n", "hello\nworld")如果是单个字符或 rune,更常见的是:
go
fmt.Printf("%c\n", 'A')
fmt.Printf("%U\n", '中')%s 适合字符串,%c 更偏字符语义,%U 适合看 Unicode 码点。
宽度和精度控制
浮点数最常见的是精度控制:
go
fmt.Printf("%.2f\n", 123.456)宽度控制也很常见:
go
fmt.Printf("%8d\n", 42)
fmt.Printf("%-8d\n", 42)这类写法在日志表格、终端输出对齐时很有用。
%w 不是打印动词,而是错误包装
它只在 fmt.Errorf 里使用:
go
err := fmt.Errorf("read config: %w", originalErr)这里的重点不是格式化输出,而是保留错误链。不要把 %w 当成普通 Printf 动词来理解。
常见误区
%v 不是万能最优解
它很方便,但很多时候表达不够精确。调试时可以先用 %v,真正需要清楚区分类型和语义时,最好换更明确的动词。
%s 不适合所有“看起来像文本”的值
如果底层是字节切片、字符、接口值,直接用 %s 不一定符合预期。
出现 %!d(string=...) 这类输出,通常是动词和类型不匹配
这不是 fmt 出 bug,而是在提醒当前占位符用错了。
一条够用的判断线
写格式化输出时,先问自己:
- 我现在是想看值、看类型,还是看 Go 语法表示。
- 当前值是整数、浮点、字符串、字符,还是指针。
- 我需要的是快速调试,还是对外稳定输出。
先把这三件事想清楚,动词基本就不会选错。
