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 |
// 补0而不是空格
fmt.Printf("|%06s|%06d|\n", "Name", 42) // 输出: |00Name|000042|
字符串格式化 (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 创建带上下文的错误信息
- 错误信息应该清晰说明问题,包含相关变量值
扫描输入
go
package main
import "fmt"
func main() {
var name string
var age byte
var salary float32
var pass bool
// 方式一 Scanln
//fmt.Println("请输入姓名:")
//fmt.Scanln(&name)
//
//fmt.Println("请输入年龄:")
//fmt.Scanln(&age)
//
//fmt.Println("请输入薪资:")
//fmt.Scanln(&salary)
//
//fmt.Println("是否通过考试:")
//fmt.Scanln(&pass)
// 方式二 Scanf
fmt.Println("请输入姓名 ,年龄 ,薪资 ,是否通过考试,使用空格分隔开")
fmt.Scanf("%s %d %f %t", &name, &age, &salary, &pass)
// 方式三 Scan
//fmt.Scan(&name, &age, &salary, &pass)
fmt.Printf("姓名:%s,年龄:%d,薪资:%f,是否通过考试:%t\n", name, age, salary, pass)
}
技巧 :
- 使用 Scanf 可以更精确控制输入格式
- 不需要严格控制输入格式并且是简单的空格分隔值使用 Scan
- 对于复杂输入,考虑使用 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)