重要
fmt 是 Go 中使用频率最高的包之一。日常开发中,三个动词覆盖 90% 场景:%v(默认格式)、%+v(带字段名)、%#v(Go 语法表示)。
环境说明
1. 输出函数速查
| 函数 | 输出位置 | 用途 |
|---|
fmt.Print | os.Stdout | 直接打印,无换行 |
fmt.Println | os.Stdout | 打印 + 空格分隔 + 换行 |
fmt.Printf | os.Stdout | 格式化打印 |
fmt.Sprintf | 返回 string | 格式化返回字符串,不输出 |
fmt.Fprintf | io.Writer | 格式化写入任意 Writer |
fmt.Errorf | 返回 error | errors.New + Sprintf,创建格式化错误 |
2. 通用动词(最常用)
| 动词 | 效果 | 示例 |
|---|
%v | 默认格式 | fmt.Printf("%v", user) → {Alice 30} |
%+v | 带字段名 | fmt.Printf("%+v", user) → {Name:Alice Age:30} |
%#v | Go 语法表示 | fmt.Printf("%#v", user) → main.User{Name:"Alice", Age:30} |
%T | 类型 | fmt.Printf("%T", user) → main.User |
%% | 百分号本身 | fmt.Printf("100%%") → 100% |
1
2
3
4
5
6
7
8
9
10
11
| type User struct {
Name string
Age int
}
u := User{Name: "Alice", Age: 30}
fmt.Printf("%v\n", u) // {Alice 30}
fmt.Printf("%+v\n", u) // {Name:Alice Age:30}
fmt.Printf("%#v\n", u) // main.User{Name:"Alice", Age:30}
fmt.Printf("%T\n", u) // main.User
|
日常调试优先用 %+v——看字段名比猜字段位置快得多。
3. 基本类型动词
| 类型 | 动词 | 说明 |
|---|
bool | %t | true / false |
int | %d | 十进制 |
int | %b | 二进制 |
int | %o | 八进制 |
int | %x / %X | 十六进制(小写/大写) |
float64 | %f | 浮点数(%.2f 两位小数) |
float64 | %e | 科学计数法 |
string | %s | 字符串 |
string | %q | 带引号的字符串(显示转义字符) |
[]byte | %s | byte 切片按字符串打印 |
| 指针 | %p | 地址 |
1
2
3
4
5
6
7
| n := 255
fmt.Printf("dec=%d bin=%b hex=%x\n", n, n, n) // dec=255 bin=11111111 hex=ff
s := "hello\nworld"
fmt.Printf("raw=%s quoted=%q\n", s, s)
// raw=hello quoted="hello\nworld"
// world
|
4. 宽度和精度控制
1
2
3
4
| fmt.Printf("|%10s|\n", "hi") // | hi| 右对齐,10 字符宽
fmt.Printf("|%-10s|\n", "hi") // |hi | 左对齐
fmt.Printf("|%010d|\n", 42) // |0000000042| 0 填充
fmt.Printf("π ≈ %.3f\n", math.Pi) // π ≈ 3.142 3 位小数
|
5. 自定义输出:fmt.Stringer
实现 String() string 方法的类型,%v / %s / Println 自动调用:
1
2
3
4
5
6
7
8
9
10
11
| type User struct {
Name string
Age int
}
func (u User) String() string {
return fmt.Sprintf("%s (%d years old)", u.Name, u.Age)
}
u := User{Name: "Alice", Age: 30}
fmt.Println(u) // Alice (30 years old)
|
实现 String() 后 %+v 和 %#v 仍然会显示struct字段名/Go语法,不会被 String() 覆盖。只有 %v / %s / 无动词的 Println 会用它。
6. 常用场景
6.1 多行字符串
1
2
3
| s := fmt.Sprintf(`User: %s
Email: %s
Role: %s`, name, email, role)
|
6.2 错误包装
1
2
3
| if err != nil {
return fmt.Errorf("get user %s failed: %w", userID, err)
}
|
%w 是 Go 1.13 引入的错误包装动词,配合 errors.Is / errors.As 使用。
6.3 调试结构体切片
1
2
3
| users := []User{{"A", 20}, {"B", 30}}
fmt.Printf("%+v\n", users)
// [{Name:A Age:20} {Name:B Age:30}]
|
7. 总结
| 场景 | 推荐 |
|---|
| 调试打印结构体 | %+v |
| 打印错误,保留调用链 | fmt.Errorf("...: %w", err) |
| 日志格式化写入文件 | fmt.Fprintf(f, ...) |
| 自定义类型可读输出 | 实现 String() string |
| 对齐输出 | %10s / %-10s |
参考链接