Go fmt占位符应按类型分组记忆:通用%v/%+v/%#v区别在详细程度;数字%d/%x/%f/%e须对号入座;字符串%s/%q/%x注意nil和编码;修饰符宽度精度需规范组合,避免panic。
Go 的 fmt 包占位符不是“记不住”,而是没理清分类逻辑——按类型分组记忆,比死背 %v %d %s 有效得多。
%v、%+v、%#v 怎么选?这三个是调试和日志最常用的,区别不在“输出什么”,而在“输出多详细”:
%v:默认格式,结构体只输出字段值,不带字段名%+v:带字段名,适合快速定位结构体内容,比如 fmt.Printf("%+v", struct{A int; B string}{1, "x"}) // {A:1 B:"x"}%#v:输出 Go 语法可复现的字面量形式,含类型信息,适合生成测试数据或反射调试注意:%v 对 nil 接口、nil 切片等输出 ,但不会 panic;而 %s 遇到 nil []byte 会 panic。
%d、%x、%f、%e 各管什么?整数、浮点、十六进制不能混用,否则结果错乱或 panic:
立即学习“go语言免费学习笔记(深入)”;
%d:有符号十进制整数(int, int8 等),uint 类型也兼容%x:小写十六进制(0xff),%X 是大写(0xFF);只接受整数,传 float64 会 panic%f:十进制浮点,如 123.450000;默认 6 位小数,可用 %.2f 控制精度%e 或 %E:科学计数法,%e 输出 1.234500e+02,%E 是 1.234500E+02
特别注意:%d 对 float64(3.14) 会截断为 3,但这是隐式转换,不报错;而 %f 对 int(5) 会自动转成 5.000000,Go 允许这种宽泛匹配。
%s、%q、%x 容易踩的坑%s 看似简单,实则边界敏感:
%s:要求参数是 string 或 []byte;传 nil []byte 会 panic,但 nil string
是合法的(输出空字符串)%q:加双引号 + 转义,适合日志中安全输出用户输入,比如 fmt.Printf("%q", "a\nb") // "a\nb"%x 对 []byte 或 string 输出十六进制字符串(无空格),% x(中间有空格)才加空格分隔别用 %s 打印非 UTF-8 字节序列——它不会报错,但可能输出乱码或截断;需要原始字节请用 %x 或 %q。
修饰符不是可选技巧,而是控制输出一致性的刚需,尤其在对齐日志或生成固定宽表格时:
%5d):右对齐,不足补空格;%-5d 左对齐%.2f):对浮点是小数位数,对字符串是最大输出长度(%.3s 截取前 3 字符)%06d:数字补零对齐,42 → 000042;但 %06s 无效(字符串不补零)%+d:强制显示正负号,+42;% d(空格)对正数加空格、负数加负号,用于对齐正负输出组合示例:
fmt.Printf("|%6.2f|%6s|\n", 3.14159, "hi") // | 3.14| hi|。注意:宽度和精度顺序不能颠倒,%.2f 合法,.2%f 语法错误。
真正难的不是记住所有占位符,而是理解哪些组合在 runtime 会 panic、哪些只是静默截断、哪些依赖参数实际类型——比如 %d 接 uintptr 在 32 位系统和 64 位系统行为不同,%v 却始终安全。线上服务里,宁可用 %v 或显式类型转换,也别赌隐式行为。