fmt 包需准确理解动词含义、参数顺序和接口行为;%v、%+v、%#v 输出结构体分别不带名、带名、语法风格;nil 值应优先用 %v;Stringer 生效需方法导出且接收者匹配,特殊动词如 %q 不调用 Stringer。

Go 的 fmt 包不是“学会几个函数就能用好”的工具,它依赖对动词含义、参数顺序和接口行为的准确理解;用错动词或忽略空格/换行规则,输出会意外截断、错位或 panic。
为什么 fmt.Printf 有时不打印换行?
fmt.Printf 不自动加换行,它只按格式字符串字面输出。你写 fmt.Printf("hello"),光标就停在 o 后面,下一条输出会紧贴着写。
- 需要换行时,显式加
\n:fmt.Printf("hello\n") - 想省事且接受换行,改用
fmt.Println(它会在末尾自动加\n,还会在参数间加空格) - 注意
fmt.Print和fmt.Println都不支持格式动词,只能原样输出值
%v、%+v、%#v 的区别到底在哪?
这三个都是通用动词,但结构体输出差异极大,调试时选错就看不到关键字段。
-
%v:默认格式,结构体只显示字段值,不带字段名 ——{123 true} -
%+v:带字段名,适合快速确认字段赋值是否正确 ——{ID:123 Active:true} -
%#v:Go 语法风格输出,能直接复制进代码当字面量用 ——main.User{ID:123, Active:true} - 嵌套结构体、指针、切片都受同样规则影响;
%+v对 map 无效(map 无字段名)
如何安全地格式化可能为 nil 的指针或接口?
直接用 %v 打印 nil 指针不会 panic,但输出是 ,容易被忽略;若用 %s 强制转字符串,nil 接口会 panic:panic: runtime error: invalid memory address or nil pointer dereference。
立即学习“go语言免费学习笔记(深入)”;
- 永远避免对未知值硬套
%s、%d等类型专属动词 - 不确定是否为 nil 时,优先用
%v或%+v - 若必须用
%s,先做非空判断:if s != nil { fmt.Printf("%s", *s) } - 接口类型(如
error)建议统一用%v,fmt内部会调用其Error()方法
自定义类型的格式化:为什么实现了 Stringer 还没生效?
实现 fmt.Stringer 接口(即 String() string 方法)后,%v、%s 等动词才会调用它;但有三个常见失效点:
- 方法接收者是值类型,但你传的是指针 —— 反之亦然;确保签名匹配:
func (u User) String() string能处理User和*User(因 Go 自动取地址),但func (u *User) String() string无法处理值类型变量 - 包内类型需导出方法名:
String()首字母必须大写 - 用了
%q(带引号字符串)或%x(十六进制)等特殊动词,它们不查Stringer,只走底层编码逻辑
动词组合、空格控制、宽度精度这些细节,在日志、CLI 输出、模板生成里全都会暴露问题;别依赖“差不多”,每个 % 后面的字符都有明确语义。










