fmt包需按场景选函数:Print/Println用于无格式拼接,Printf需格式字符串;%v、%+v、%#v输出格式不同;字符串拼接优先用+或Join;Scan系列易出错,推荐bufio.Scanner+strconv。

fmt 包不是“学完就会”的工具,它得按场景选函数、看动词、盯类型,否则 fmt.Printf 打印出空字符串或 panic 是常事。
什么时候该用 fmt.Print、fmt.Println 还是 fmt.Printf
三者根本区别不在“有没有换行”,而在“要不要格式控制”:
-
fmt.Print和fmt.Println是纯拼接:自动调用每个参数的String()方法(如果实现了),不支持占位符,fmt.Println只多加一个\n -
fmt.Printf必须带格式字符串,比如"%s: %d",漏写或类型不匹配会静默截断或 panic - 调试时别图省事全用
fmt.Println(v)——遇到nilslice 或未导出字段结构体,输出可能是&{...}或空,看不出实际内容;该用fmt.Printf("%+v\n", v)
%v、%+v、%#v 三个动词到底差在哪
它们都用于“通用值输出”,但细节决定是否能看清数据结构:
-
%v:默认格式,struct 只打字段值,不标字段名;interface{} 类型会显示底层值 -
%+v:struct 字段名 + 值一起打,比如{Name:"foo" Age:25};map、slice 不变 -
%#v:Go 语法风格输出,可直接复制进代码当字面量用,比如map[string]int{"a": 1, "b": 2} - 注意:
%+v对嵌套 struct 有效,但对匿名字段(内嵌)仍可能省略字段名;想彻底展开用spew.Dump(非标准库)
字符串拼接别用 fmt.Sprintf,除非真需要格式化
单纯拼几个变量,fmt.Sprintf 性能差、易出错:
立即学习“go语言免费学习笔记(深入)”;
- 它会分配新字符串 + 解析格式串 + 类型反射,比
strings.Join或+拼接慢 3–10 倍 - 常见错误:
fmt.Sprintf("id=%d", id)中id是string类型 → panic:panic: unexpected type string - 替代方案:
- 固定拼接:
"id=" + id(id是 string) - 多字符串:
strings.Join([]string{"a", "b", c}, "-") - 真要格式化(如补零、对齐):
fmt.Sprintf("id=%06d", 123)才合理
- 固定拼接:
fmt.Scan 系列读输入的坑
从标准输入读值看似简单,实际最容易卡住或读错:
-
fmt.Scan遇到空格/换行就停,fmt.Scanf("%s", &s)永远读不到含空格的字符串 -
fmt.Scanln要求整行输完且以\n结尾,否则阻塞;它不吞掉换行符,下一次Scan可能立刻返回空 - 安全做法:用
bufio.Scanner读行,再用strconv转数字,比如:
scanner := bufio.NewScanner(os.Stdin)
if scanner.Scan() {
line := scanner.Text()
if n, err := strconv.Atoi(line); err == nil {
// 处理 n
}
}
标准库的 fmt.Scan 系列没有超时、没缓冲控制、不处理编码,线上服务别碰。










