Go 标准库深入学习:fmt 包详解
fmt 包概述
fmt 是 Go 语言中最基础也最常用的标准库之一,它提供了格式化 I/O 功能,主要用于打印输出和格式化字符串。本文将深入探讨 fmt 包的各个方面,包括格式化动词、扫描函数、格式化函数等核心功能。
格式化输出
Print 系列函数
fmt 提供了多种打印函数:
// 标准输出
fmt.Print("Hello, ") // 不换行
fmt.Println("World!") // 自动换行
fmt.Printf("Number: %d\n", 42) // 格式化输出
// 格式化字符串
s := fmt.Sprintf("Value: %v", 3.14)
// 拼接字符串
builder := &strings.Builder{}
fmt.Fprintf(builder, "Built: %s", "string builder")
格式化动词
fmt 的格式化动词非常丰富:
// 通用格式化
fmt.Printf("%v\n", struct{ A int }{1}) // 默认格式
fmt.Printf("%+v\n", struct{ A int }{1}) // 带字段名
fmt.Printf("%#v\n", struct{ A int }{1}) // Go语法表示
// 布尔值
fmt.Printf("%t\n", true)
// 整数
fmt.Printf("%d\n", 255) // 十进制
fmt.Printf("%b\n", 255) // 二进制
fmt.Printf("%o\n", 255) // 八进制
fmt.Printf("%x\n", 255) // 十六进制
// 浮点数
fmt.Printf("%f\n", 3.1415926535) // 默认精度
fmt.Printf("%.2f\n", 3.1415926535) // 指定精度
fmt.Printf("%e\n", 3.1415926535) // 科学计数法
// 字符串和切片
fmt.Printf("%s\n", "hello") // 字符串
fmt.Printf("%q\n", "hello") // 带引号字符串
fmt.Printf("%x\n", "hello") // 十六进制
// 指针
v := 42
fmt.Printf("%p\n", &v) // 指针地址
宽度和精度
可以在动词前指定宽度和精度:
fmt.Printf("|%6d|%6d|\n", 12, 345) // 右对齐宽度6
fmt.Printf("|%-6s|%-6s|\n", "foo", "b") // 左对齐宽度6
fmt.Printf("|%6.2f|\n", 1.2) // 宽度6精度2
fmt.Printf("|%*.*f|\n", 6, 2, 1.2) // 动态宽度和精度
输入扫描
Scan 系列函数
fmt 也提供了从标准输入读取数据的功能:
var name string
var age int
// 从标准输入读取,空格分隔
fmt.Scan(&name, &age)
// 支持格式化的扫描
fmt.Scanf("%s is %d years old", &name, &age)
// 扫描一行
input := "Hello 25"
fmt.Sscan(input, &name, &age)
// 从字符串格式化扫描
fmt.Sscanf("Name: Alice, Age: 25", "Name: %s, Age: %d", &name, &age)
扫描注意事项
// 处理扫描错误
n, err := fmt.Sscanf("Invalid input", "%d", &age)
if err != nil {
fmt.Println("Parse error:", err)
fmt.Println("Successfully parsed items:", n)
}
自定义类型的格式化
可以为自定义类型实现 fmt.Stringer 和 fmt.Formatter 接口:
type Point struct {
X, Y int
}
// 实现 Stringer 接口
func (p Point) String() string {
return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}
// 实现 Formatter 接口
func (p Point) Format(f fmt.State, verb rune) {
switch verb {
case 'v':
if f.Flag('+') {
fmt.Fprintf(f, "Point{X:%d, Y:%d}", p.X, p.Y)
} else {
fmt.Fprintf(f, "(%d, %d)", p.X, p.Y)
}
case 'P':
fmt.Fprintf(f, "Point at (%d, %d)", p.X, p.Y)
default:
fmt.Fprintf(f, "%%!%c(Point=%v)", verb, p)
}
}
func main() {
p := Point{X: 1, Y: 2}
fmt.Println(p) // 调用 String()
fmt.Printf("%v\n", p) // 调用 Format()
fmt.Printf("%+v\n", p)
fmt.Printf("%P\n", p)
fmt.Printf("%d\n", p) // 错误格式化
}
错误处理
fmt 包还提供了一些错误处理工具:
// 创建带格式的错误
err := fmt.Errorf("user %q (id %d) not found", "alice", 42)
// 错误值可以包含更多上下文
if _, ok := err.(interface{ Unwrap() error }); ok {
fmt.Println("Error implements Unwrap()")
}
性能考虑
// 多次拼接字符串时,使用 fmt.Fprint 比 fmt.Sprintf 更高效
var sb strings.Builder
for i := 0; i < 100; i++ {
fmt.Fprintf(&sb, "%d", i)
}
总结
fmt 包是 Go 语言中非常强大和灵活的格式化 I/O 工具。掌握它的格式化动词和各种函数,可以让你写出更加清晰和高效的输出代码。无论是简单的打印调试还是复杂的格式化需求,fmt 包都能胜任。
文末预告
下一期我们将深入学习 Go 语言的 net/http
标准库,探讨 HTTP 客户端和服务器的实现原理,以及如何构建高效的 Web 应用。敬请期待!