fmt - 格式化 I/O
概述
fmt 包实现了格式化 I/O 功能,提供类似于 C 的 printf 和 scanf 的函数。
包导入:
import "fmt"
基本使用:
// 格式化输出
fmt.Printf("Hello, %s! You are %d years old.\n", "Alice", 25)
// 打印到标准输出
fmt.Println("Hello, World!")
// 格式化字符串
s := fmt.Sprintf("Result: %v", 42)
// 格式化错误
err := fmt.Errorf("invalid value: %d", -1)
典型示例:
示例 1:完整的日志输出系统:
package main
import (
"fmt"
"os"
"time"
)
func main() {
// 信息日志
fmt.Printf("[%s] INFO: Application started\n", time.Now().Format(time.RFC3339))
// 警告日志
fmt.Fprintf(os.Stderr, "[%s] WARNING: Low memory\n", time.Now().Format(time.RFC3339))
// 错误日志
err := fmt.Errorf("connection failed: %w", os.ErrNotExist)
fmt.Fprintf(os.Stderr, "[%s] ERROR: %v\n", time.Now().Format(time.RFC3339), err)
// 调试信息
debug := true
if debug {
fmt.Printf("[DEBUG] Variables: %+v\n", map[string]interface{}{
"user": "admin",
"role": "superuser",
"active": true,
})
}
}
运行:
$ ./logger
[2024-01-01T12:00:00Z] INFO: Application started
[DEBUG] Variables: map[active:true role:superuser user:admin]
示例 2:数据报表生成器:
package main
import (
"bytes"
"fmt"
)
func main() {
// 生成格式化报表
var buf bytes.Buffer
// 表头
fmt.Fprintln(&buf, "┌─────────┬────────────┬──────────┐")
fmt.Fprintln(&buf, "│ ID │ Name │ Score │")
fmt.Fprintln(&buf, "├─────────┼────────────┼──────────┤")
// 数据行
students := []struct {
ID int
Name string
Score float64
}{
{1, "Alice", 95.5},
{2, "Bob", 87.3},
{3, "Charlie", 92.8},
}
for _, s := range students {
fmt.Fprintf(&buf, "│ %7d │ %-10s │ %8.2f │\n", s.ID, s.Name, s.Score)
}
// 表尾
fmt.Fprintln(&buf, "└─────────┴────────────┴──────────┘")
// 输出
fmt.Println(buf.String())
// 统计信息
total := 0.0
for _, s := range students {
total += s.Score
}
avg := total / float64(len(students))
fmt.Printf("\n平均分:%.2f\n", avg)
}
运行:
$ ./report
┌─────────┬────────────┬──────────┐
│ ID │ Name │ Score │
├─────────┼────────────┼──────────┤
│ 1 │ Alice │ 95.50 │
│ 2 │ Bob │ 87.30 │
│ 3 │ Charlie │ 92.80 │
└─────────┴────────────┴──────────┘
平均分:91.87
一、Print 系列函数
打印带换行符
Println(a …any) (n int, err error)
说明:
- 打印参数并在末尾添加换行符
- 参数之间用空格分隔
- 返回写入的字节数和错误
定义/实现:
func Println(a ...any) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
示例:
package main
import "fmt"
func main() {
fmt.Println("Hello") // Hello\n
fmt.Println("A", "B", "C") // A B C\n
fmt.Println(1, 2, 3) // 1 2 3\n
fmt.Println() // \n
}
打印不带换行符
Print(a …any) (n int, err error)
说明:
- 打印参数但不添加换行符
- 参数之间用空格分隔
定义/实现:
func Print(a ...any) (n int, err error) {
return Fprint(os.Stdout, a...)
}
示例:
package main
import "fmt"
func main() {
fmt.Print("Hello") // Hello
fmt.Print("A", "B", "C") // ABC
fmt.Print(1, 2, 3) // 123
fmt.Print("Score: ", 95) // Score: 95
}
二、Printf 系列函数
格式化打印
Printf(format string, a …any) (n int, err error)
说明:
- 根据格式字符串打印
- 返回写入的字节数和错误
格式动词:
%v- 默认格式%+v- 结构体字段名%#v- Go 语法格式%T- 类型%t- bool 的 true/false%s- 字符串%q- 带引号的字符串%d- 十进制整数%b- 二进制%x- 十六进制%f- 浮点数%e- 科学计数法%p- 指针地址
定义/实现:
func Printf(format string, a ...any) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}
示例:
package main
import "fmt"
func main() {
name := "Alice"
age := 25
score := 95.5
// 基本格式
fmt.Printf("Name: %s, Age: %d\n", name, age)
// 浮点数格式
fmt.Printf("Score: %f\n", score) // 95.500000
fmt.Printf("Score: %.2f\n", score) // 95.50
fmt.Printf("Score: %e\n", score) // 9.550000e+01
// 整数格式
n := 42
fmt.Printf("Dec: %d, Bin: %b, Hex: %x\n", n, n, n)
// 结构体格式
type Person struct {
Name string
Age int
}
p := Person{"Bob", 30}
fmt.Printf("%v\n", p) // {Bob 30}
fmt.Printf("%+v\n", p) // {Name:Bob Age:30}
fmt.Printf("%#v\n", p) // main.Person{Name:"Bob", Age:30}
// 类型
fmt.Printf("Type: %T\n", p) // main.Person
// 指针
fmt.Printf("Address: %p\n", &p)
// 布尔
fmt.Printf("True: %t, False: %t\n", true, false)
// 字符串
fmt.Printf("%s\n", "hello") // hello
fmt.Printf("%q\n", "hello") // "hello"
fmt.Printf("%x\n", "hello") // 68656c6c6f
}
运行:
$ ./program
Name: Alice, Age: 25
Score: 95.500000
Score: 95.50
Score: 9.550000e+01
Dec: 42, Bin: 101010, Hex: 2a
{Bob 30}
{Name:Bob Age:30}
main.Person{Name:"Bob", Age:30}
Type: main.Person
Address: 0xc00000a000
True: true, False: false
hello
"hello"
68656c6c6f
格式化到字符串
Sprintf(format string, a …any) string
说明:
- 根据格式字符串格式化并返回字符串
- 不输出,只返回结果
定义/实现:
func Sprintf(format string, a ...any) string {
var buf []byte
// ... 格式化逻辑
return string(buf)
}
示例:
package main
import (
"fmt"
)
func main() {
// 基本使用
s := fmt.Sprintf("Hello, %s!", "World")
fmt.Println(s) // Hello, World!
// 数字格式化
price := fmt.Sprintf("$%.2f", 19.99)
fmt.Println(price) // $19.99
// 百分比
percent := fmt.Sprintf("%.1f%%", 75.5)
fmt.Println(percent) // 75.5%
// 填充和对齐
fmt.Printf("|%10s|\n", "hello") // | hello|
fmt.Printf("|%-10s|\n", "hello") // |hello |
fmt.Printf("|%010d|\n", 42) // |0000000042|
// 动态宽度
width := 10
fmt.Printf("|%*s|\n", width, "hello") // | hello|
}
三、Fprint 系列函数
格式化输出到 io.Writer
Fprintf(w io.Writer, format string, a …any) (n int, err error)
说明:
- 格式化输出到指定的 io.Writer
- 返回写入的字节数和错误
定义/实现:
func Fprintf(w io.Writer, format string, a ...any) (n int, err error) {
// ... 格式化并写入
}
示例:
package main
import (
"fmt"
"os"
"strings"
)
func main() {
// 输出到文件
file, _ := os.Create("output.txt")
fmt.Fprintf(file, "Hello, %s!\n", "File")
file.Close()
// 输出到字符串缓冲区
var buf strings.Builder
fmt.Fprintf(&buf, "Name: %s\n", "Alice")
fmt.Fprintf(&buf, "Age: %d\n", 25)
fmt.Println(buf.String())
// 输出到标准错误
fmt.Fprintf(os.Stderr, "Error: something went wrong\n")
}
打印到 io.Writer
Fprint(w io.Writer, a …any) (n int, err error)
说明:
- 打印参数到 io.Writer
- 参数之间用空格分隔
定义/实现:
func Fprint(w io.Writer, a ...any) (n int, err error) {
// ... 打印逻辑
}
示例:
package main
import (
"fmt"
"os"
"strings"
)
func main() {
// 输出到字符串
var buf strings.Builder
fmt.Fprint(&buf, "A", "B", "C")
fmt.Println(buf.String()) // ABC
// 输出到文件
file, _ := os.Create("test.txt")
fmt.Fprint(file, "Hello, File!")
file.Close()
}
打印带换行到 io.Writer
Fprintln(w io.Writer, a …any) (n int, err error)
说明:
- 打印参数并添加换行符
- 参数之间用空格分隔
定义/实现:
func Fprintln(w io.Writer, a ...any) (n int, err error) {
// ... 打印逻辑
}
示例:
package main
import (
"fmt"
"os"
"strings"
)
func main() {
// 输出到字符串
var buf strings.Builder
fmt.Fprintln(&buf, "Line 1")
fmt.Fprintln(&buf, "Line 2")
fmt.Print(buf.String())
// 输出到标准错误
fmt.Fprintln(os.Stderr, "Error message")
}
四、Sprint 系列函数
格式化为字符串
Sprint(a …any) string
说明:
- 将参数格式化为字符串
- 参数之间用空格分隔
定义/实现:
func Sprint(a ...any) string {
// ... 格式化逻辑
}
示例:
package main
import (
"fmt"
)
func main() {
s := fmt.Sprint("A", "B", "C")
fmt.Println(s) // ABC
s2 := fmt.Sprint(1, 2, 3)
fmt.Println(s2) // 123
s3 := fmt.Sprint("Score: ", 95)
fmt.Println(s3) // Score: 95
}
格式化为带换行的字符串
Sprintln(a …any) string
说明:
- 格式化参数并添加换行符
- 参数之间用空格分隔
定义/实现:
func Sprintln(a ...any) string {
// ... 格式化逻辑
}
示例:
package main
import (
"fmt"
)
func main() {
s := fmt.Sprintln("Hello")
fmt.Print(s) // Hello\n
s2 := fmt.Sprintln("A", "B", "C")
fmt.Print(s2) // A B C\n
}
五、Errorf 函数
格式化错误
Errorf(format string, a …any) error
说明:
- 根据格式字符串创建错误
- 等价于
errors.New(Sprintf(...))
定义/实现:
func Errorf(format string, a ...any) error {
return &errorString{s: Sprintf(format, a...)}
}
示例:
package main
import (
"errors"
"fmt"
)
func main() {
// 基本错误
err := fmt.Errorf("invalid value: %d", -1)
fmt.Println(err)
// 包装错误
baseErr := errors.New("base error")
wrappedErr := fmt.Errorf("wrapped: %w", baseErr)
fmt.Println(wrappedErr)
// 错误链
err1 := errors.New("level 1")
err2 := fmt.Errorf("level 2: %w", err1)
err3 := fmt.Errorf("level 3: %w", err2)
fmt.Println(err3)
// 检查错误链
if errors.Is(err3, err1) {
fmt.Println("包含 level 1 错误")
}
// 多重包装
err = fmt.Errorf("timeout: %w",
fmt.Errorf("connection: %w",
errors.New("failed")))
fmt.Println(err)
}
运行:
$ ./program
invalid value: -1
wrapped: base error
level 3: level 2: level 1
包含 level 1 错误
timeout: connection: failed
六、Scan 系列函数
从标准输入扫描
Scan(a …any) (n int, err error)
说明:
- 从标准输入扫描数据
- 以空格分隔
- 返回扫描的项目数和错误
定义/实现:
func Scan(a ...any) (n int, err error) {
return Fscan(os.Stdin, a...)
}
示例:
package main
import (
"fmt"
)
func main() {
var name string
var age int
fmt.Print("Enter name and age: ")
n, err := fmt.Scan(&name, &age)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d items: %s, %d\n", n, name, age)
}
运行:
$ ./program
Enter name and age: Alice 25
Scanned 2 items: Alice, 25
格式化扫描
Scanf(format string, a …any) (n int, err error)
说明:
- 根据格式字符串扫描
- 返回扫描的项目数和错误
定义/实现:
func Scanf(format string, a ...any) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
示例:
package main
import (
"fmt"
)
func main() {
var name string
var age int
fmt.Print("Enter name and age (format: name:age): ")
n, err := fmt.Scanf("%s:%d", &name, &age)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d items: %s, %d\n", n, name, age)
}
运行:
$ ./program
Enter name and age (format: name:age): Alice:25
Scanned 2 items: Alice, 25
扫描一行
Scanln(a …any) (n int, err error)
说明:
- 扫描一行数据
- 以空格分隔,遇到换行结束
定义/实现:
func Scanln(a ...any) (n int, err error) {
return Fscanln(os.Stdin, a...)
}
示例:
package main
import (
"fmt"
)
func main() {
var a, b, c int
fmt.Print("Enter three numbers: ")
n, err := fmt.Scanln(&a, &b, &c)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d items: %d, %d, %d\n", n, a, b, c)
}
运行:
$ ./program
Enter three numbers: 1 2 3
Scanned 3 items: 1, 2, 3
七、Fscan 系列函数
从 io.Reader 扫描
Fscan(r io.Reader, a …any) (n int, err error)
说明:
- 从 io.Reader 扫描数据
- 以空格分隔
定义/实现:
func Fscan(r io.Reader, a ...any) (n int, err error) {
// ... 扫描逻辑
}
示例:
package main
import (
"fmt"
"strings"
)
func main() {
input := strings.NewReader("100 200 300")
var a, b, c int
n, err := fmt.Fscan(input, &a, &b, &c)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d: %d, %d, %d\n", n, a, b, c)
}
格式化从 io.Reader 扫描
Fscanf(r io.Reader, format string, a …any) (n int, err error)
说明:
- 根据格式从 io.Reader 扫描
定义/实现:
func Fscanf(r io.Reader, format string, a ...any) (n int, err error) {
// ... 扫描逻辑
}
示例:
package main
import (
"fmt"
"strings"
)
func main() {
input := strings.NewReader("Alice:25:95.5")
var name string
var age int
var score float64
n, err := fmt.Fscanf(input, "%s:%d:%f", &name, &age, &score)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d: %s, %d, %.1f\n", n, name, age, score)
}
从 io.Reader 扫描一行
Fscanln(r io.Reader, a …any) (n int, err error)
说明:
- 从 io.Reader 扫描一行
- 遇到换行结束
定义/实现:
func Fscanln(r io.Reader, a ...any) (n int, err error) {
// ... 扫描逻辑
}
示例:
package main
import (
"fmt"
"strings"
)
func main() {
input := strings.NewReader("1 2 3\n4 5 6\n")
var a, b, c int
n, err := fmt.Fscanln(input, &a, &b, &c)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d: %d, %d, %d\n", n, a, b, c)
}
八、Sscan 系列函数
从字符串扫描
Sscan(str string, a …any) (n int, err error)
说明:
- 从字符串扫描数据
- 以空格分隔
定义/实现:
func Sscan(str string, a ...any) (n int, err error) {
// ... 扫描逻辑
}
示例:
package main
import (
"fmt"
)
func main() {
input := "100 200 300"
var a, b, c int
n, err := fmt.Sscan(input, &a, &b, &c)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d: %d, %d, %d\n", n, a, b, c)
}
格式化从字符串扫描
Sscanf(str string, format string, a …any) (n int, err error)
说明:
- 根据格式从字符串扫描
定义/实现:
func Sscanf(str string, format string, a ...any) (n int, err error) {
// ... 扫描逻辑
}
示例:
package main
import (
"fmt"
)
func main() {
input := "Alice:25:95.5"
var name string
var age int
var score float64
n, err := fmt.Sscanf(input, "%s:%d:%f", &name, &age, &score)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d: %s, %d, %.1f\n", n, name, age, score)
}
从字符串扫描一行
Sscanln(str string, a …any) (n int, err error)
说明:
- 从字符串扫描,遇到换行或字符串结束
定义/实现:
func Sscanln(str string, a ...any) (n int, err error) {
// ... 扫描逻辑
}
示例:
package main
import (
"fmt"
)
func main() {
input := "1 2 3"
var a, b, c int
n, err := fmt.Sscanln(input, &a, &b, &c)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d: %d, %d, %d\n", n, a, b, c)
}
九、Append 系列函数
格式化追加到切片
Appendf(b []byte, format string, a …any) []byte
说明:
- 格式化并追加到字节切片
- 返回扩展后的切片
定义/实现:
func Appendf(b []byte, format string, a ...any) []byte {
// ... 格式化并追加
}
示例:
package main
import (
"fmt"
)
func main() {
// 基本使用
b := []byte("Hello, ")
b = fmt.Appendf(b, "%s!", "World")
fmt.Println(string(b)) // Hello, World!
// 数字格式化
b = fmt.Appendf(nil, "Score: %.2f", 95.5)
fmt.Println(string(b)) // Score: 95.50
// 多次追加
b = []byte{}
b = fmt.Appendf(b, "Name: %s\n", "Alice")
b = fmt.Appendf(b, "Age: %d\n", 25)
b = fmt.Appendf(b, "Score: %.1f\n", 95.5)
fmt.Print(string(b))
}
运行:
$ ./program
Hello, World!
Score: 95.50
Name: Alice
Age: 25
Score: 95.5
追加到切片
Append(b []byte, a …any) []byte
说明:
- 将参数追加到字节切片
- 参数之间用空格分隔
定义/实现:
func Append(b []byte, a ...any) []byte {
// ... 追加逻辑
}
示例:
package main
import (
"fmt"
)
func main() {
b := []byte("Data: ")
b = fmt.Append(b, 1, 2, 3)
fmt.Println(string(b)) // Data: 1 2 3
b = fmt.Append(nil, "A", "B", "C")
fmt.Println(string(b)) // A B C
}
追加带换行到切片
Appendln(b []byte, a …any) []byte
说明:
- 追加参数并添加换行符
定义/实现:
func Appendln(b []byte, a ...any) []byte {
// ... 追加逻辑
}
示例:
package main
import (
"fmt"
)
func main() {
b := []byte{}
b = fmt.Appendln(b, "Line 1")
b = fmt.Appendln(b, "Line 2")
b = fmt.Appendln(b, "Line 3")
fmt.Print(string(b))
}
运行:
$ ./program
Line 1
Line 2
Line 3
快速参考
格式动词
| 动词 | 说明 | 示例 |
|---|---|---|
%v | 默认格式 | fmt.Printf("%v", 42) |
%+v | 结构体字段名 | fmt.Printf("%+v", person) |
%#v | Go 语法格式 | fmt.Printf("%#v", person) |
%T | 类型 | fmt.Printf("%T", person) |
%t | 布尔 | fmt.Printf("%t", true) |
%s | 字符串 | fmt.Printf("%s", "hello") |
%q | 带引号字符串 | fmt.Printf("%q", "hello") |
%d | 十进制 | fmt.Printf("%d", 42) |
%b | 二进制 | fmt.Printf("%b", 42) |
%x | 十六进制 | fmt.Printf("%x", 42) |
%f | 浮点数 | fmt.Printf("%f", 3.14) |
%e | 科学计数法 | fmt.Printf("%e", 3.14) |
%p | 指针地址 | fmt.Printf("%p", &x) |
Print 系列
| 函数 | 说明 | 返回值 |
|---|---|---|
Print | 打印,无换行 | (n, err) |
Println | 打印,有换行 | (n, err) |
Printf | 格式化打印 | (n, err) |
Fprint | 打印到 Writer | (n, err) |
Fprintln | 打印到 Writer+ 换行 | (n, err) |
Fprintf | 格式化打印到 Writer | (n, err) |
Sprint | 格式化为字符串 | string |
Sprintln | 格式化为字符串 + 换行 | string |
Sprintf | 格式化字符串 | string |
Scan 系列
| 函数 | 输入源 | 分隔符 |
|---|---|---|
Scan | 标准输入 | 空格 |
Scanf | 标准输入 | 格式 |
Scanln | 标准输入 | 空格,换行结束 |
Fscan | io.Reader | 空格 |
Fscanf | io.Reader | 格式 |
Fscanln | io.Reader | 空格,换行结束 |
Sscan | 字符串 | 空格 |
Sscanf | 字符串 | 格式 |
Sscanln | 字符串 | 空格,结束 |
Append 系列
| 函数 | 说明 |
|---|---|
Append | 追加到 []byte |
Appendf | 格式化追加到 []byte |
Appendln | 追加 + 换行到 []byte |
错误处理
| 函数 | 说明 |
|---|---|
Errorf | 格式化创建错误 |
最后更新:2026-04-03
Go 版本:Go 1.23+