fmt.Printf动词必须与值类型严格匹配,否则报错;%v通用但无类型信息,%+v显字段名,%#v输出可复制的Go语法,%q转义字符串;需手动加\n换行;Sprintf用于构造字符串,Printf用于直接输出。

Go 的 fmt.Printf 怎么写对格式动词
动词不对,输出就不是你想要的——比如用 %d 打印字符串会 panic,用 %s 打印 int 会报错 fmt: %s format verb for int。Go 不做隐式类型转换,动词必须和值类型匹配。
常见组合直接记牢:
-
%v:万能打印,结构体、切片、map 都能看内容(但不带类型信息) -
%+v:结构体字段名+值一起打,调试时比%v有用得多 -
%#v:Go 语法风格输出,可直接复制粘贴当代码用(比如map[string]int{"a": 1}) -
%q:字符串加双引号 + 转义,适合看含空格或控制字符的字符串 -
%t只给bool,%f给浮点,%x给整数转小写十六进制
为什么 fmt.Printf 后面要加换行符
它不会自动换行,不加 \n,输出会黏在命令行提示符前面,看着像卡了。这不是 bug,是设计如此——和 C 的 printf 保持一致,方便拼接输出。
容易踩的坑:
立即学习“go语言免费学习笔记(深入)”;
- 写
fmt.Printf("name: %s", name),结果下一行 shell 提示符紧贴着输出,误以为程序没结束 - 日志里漏
\n,多条日志挤成一行,grep 不出来 - 用
fmt.Print或fmt.Println替代?可以,但Println会强制加换行且不能用格式动词,灵活性下降
建议:调试阶段统一用 fmt.Printf("%v\n", x),上线后按需调整。
fmt.Sprintf 和 fmt.Printf 到底该用谁
核心区别就一条:要不要立刻输出到终端。需要拼字符串存起来、传参、写文件,就用 Sprintf;只是临时看一眼,用 Printf 更直觉。
性能差异很小,但要注意:
-
Sprintf分配新字符串,高频调用(比如循环里)可能增加 GC 压力 -
Printf写os.Stdout,如果 stdout 被重定向到慢设备(如网络 socket),会阻塞 - 别把
Sprintf当“安全版 Printf”——类型错照样 panic,动词校验一点不少
示例:构造日志消息
msg := fmt.Sprintf("user %s logged in at %v", username, time.Now())
而不是
fmt.Printf("user %s logged in at %v", username, time.Now()) // 缺 \n,还不能存
结构体字段为空时 %v 输出什么
零值照常输出:0、""、false、nil。但如果你用 %+v,字段名还在,一眼能看出哪些字段根本没赋值。
容易忽略的细节:
- 嵌套结构体的零值不会被省略,哪怕整个子结构都是零值
- 指针字段为
nil时,%v输出<nil>,不是崩溃 - interface{} 类型变量存了 nil,
%v输出<nil>;但如果 interface{} 本身是 nil,%v还是输出<nil>—— 表面一样,含义不同,调试时得结合上下文判断
想快速确认结构体是否全零?目前没内置函数,得自己写比较逻辑,别指望格式化输出替你判断。



















