Go fmt 标准库使用指南
本文内容基于 AI 生成结果整理,可能包含不准确信息,仅供参考使用。
fmt 是 Go 语言中最常用的标准库之一,用于格式化输入输出操作
基本打印函数
fmt.Print / fmt.Println / fmt.Printf
go
package main
import "fmt"
func main() {
// fmt.Print - 不换行打印
fmt.Print("Hello, ") // 输出: Hello,
fmt.Print("World!\n") // 输出: World! 并换行
// fmt.Println - 自动换行打印
fmt.Println("Hello, World!") // 输出: Hello, World! 并换行
// fmt.Printf - 格式化打印
name := "Alice"
age := 25
fmt.Printf("Name: %s, Age: %d\n", name, age) // 输出: Name: Alice, Age: 25
}
技巧:
- 使用 Println 可以避免手动添加\n
- Printf 的格式化字符串中,%v 是通用占位符,可以自动识别类型
格式化占位符
常用占位符:
占位符 | 说明 | 示例 |
---|---|---|
%v | 默认格式的值 | fmt.Printf("%v", x) |
%+v | 结构体字段名+值 | fmt.Printf("%+v", s) |
%#v | Go 语法表示 | fmt.Printf("%#v", x) |
%T | 类型 | fmt.Printf("%T", x) |
%d | 十进制整数 | fmt.Printf("%d", 42) |
%f | 浮点数 | fmt.Printf("%f", 3.14) |
%s | 字符串 | fmt.Printf("%s", "hello") |
%p | 指针地址 | fmt.Printf("%p", &x) |
%% | 百分号 | fmt.Printf("%%") |
优雅使用技巧 :
go
user := struct {
Name string
Age int
}{"Bob", 30}
// 打印结构体时显示字段名
fmt.Printf("%+v\n", user) // 输出: {Name:Bob Age:30}
// 查看变量的Go语法表示
fmt.Printf("%#v\n", user) // 输出: struct { Name string; Age int }{Name:"Bob", Age:30}
// 自动宽度控制
fmt.Printf("|%6s|%6d|\n", "Name", 42) // 输出: | Name| 42|
fmt.Printf("|%-6s|%-6d|\n", "Name", 42) // 输出: |Name |42 |
字符串格式化 (fmt.Sprintf)
go
// 将格式化结果作为字符串返回
msg := fmt.Sprintf("At %v, temperature is %.1f°C", time.Now(), 23.456)
fmt.Println(msg) // 输出类似: At 2023-10-01 12:34:56 +0800 CST, temperature is 23.5°C
技巧 :
- 使用 Sprintf 构建复杂字符串比字符串拼接更清晰
- 可以结合%*语法动态控制宽度和精度
错误格式化 (fmt.Errorf)
go
func divide(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide %d by zero", a)
}
return a / b, nil
}
优雅使用 :
- 使用 Errorf 创建带上下文的错误信息
- 错误信息应该清晰说明问题,包含相关变量值
扫描输入 (fmt.Scan 系列)
go
var name string
var age int
fmt.Print("Enter name and age: ")
// 从标准输入读取
count, err := fmt.Scan(&name, &age)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Read %d items: %s is %d years old\n", count, name, age)
技巧 :
- 使用 Scanf 可以更精确控制输入格式
- 对于复杂输入,考虑使用 bufio.Scanner 代替
高级技巧
自定义类型的格式化
go
type Point struct {
X, Y int
}
func (p Point) String() string {
return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}
func main() {
p := Point{3, 4}
fmt.Println(p) // 输出: (3,4)
}
动态宽度和精度
go
width := 8
precision := 3
value := 3.1415926
fmt.Printf("%*.*f", width, precision, value) // 输出: " 3.142"
重定向输出
go
var buf bytes.Buffer
fmt.Fprintf(&buf, "Hello, %s!", "World")
fmt.Println(buf.String()) // 输出: Hello, World!
性能考虑
- 对于高性能场景,避免频繁使用 fmt 函数,考虑使用 strconv 等更底层的包
- 在循环中构建字符串时,strings.Builder 通常比 fmt.Sprintf 更高效
常见使用模式
日志记录
go
fmt.Printf("[%s] %-10s %s\n", time.Now().Format("2006-01-02 15:04:05"), "INFO", "Application started")
表格输出
go
fmt.Printf("|%-15s|%10s|%10s|\n", "Name", "Age", "Score")
fmt.Printf("|%-15s|%10d|%10.2f|\n", "Alice", 25, 95.5)
fmt.Printf("|%-15s|%10d|%10.2f|\n", "Bob", 30, 88.75)
调试输出
go
// 使用%#v查看完整结构
fmt.Printf("%#v\n", complexStruct)