Go 标准库与工具链

2 minIntermediate2026/6/14

io/os/net/http/filepath/encoding/json/time 等核心包、go test/bench/vet/fmt/doc、构建标签、cgo 与 Go 工具链详解。

1. 核心 I/O 包

1.1 io 包

import "io"

// 核心接口
type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }
type Closer interface { Close() error }
type Seeker interface { Seek(offset int64, whence int) (int64, error) }

// 常用函数
data, err := io.ReadAll(reader)           // 读取全部内容
n, err := io.Copy(dst, src)               // 从 src 拷贝到 dst
n, err := io.CopyN(dst, src, 1024)        // 拷贝 N 字节
written, err := io.WriteString(w, "hello") // 写入字符串

// io.MultiReader / MultiWriter
r := io.MultiReader(r1, r2, r3)  // 合并多个 Reader
w := io.MultiWriter(w1, w2, w3)  // 同时写入多个 Writer

// io.TeeReader — 同时读取和写入
var buf bytes.Buffer
tee := io.TeeReader(resp.Body, &buf)
data, _ := io.ReadAll(tee) // data 和 buf 内容相同

// io.Pipe — 内存同步管道
pr, pw := io.Pipe()
go func() {
    pw.Write([]byte("hello"))
    pw.Close()
}()
io.ReadAll(pr) // "hello"

1.2 bufio 包

import "bufio"

// 带缓冲读取
reader := bufio.NewReader(os.Stdin)
line, _ := reader.ReadString('\n')    // 读到分隔符
line, _ := reader.ReadBytes('\n')     // 读到分隔符(返回字节)
ch, _, _ := reader.ReadRune()         // 读一个 rune
word, _ := reader.ReadString(' ')     // 读到空格

// 带缓冲写入
writer := bufio.NewWriter(os.Stdout)
writer.WriteString("hello")
writer.Flush() // 必须刷新

// Scanner — 按行/自定义分割读取
scanner := bufio.NewScanner(file)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
    log.Fatal(err)
}

// 自定义分割
scanner := bufio.NewScanner(reader)
scanner.Split(bufio.ScanWords) // 按单词分割

1.3 fmt 包

// 格式化输出
fmt.Printf("Name: %s, Age: %d\n", "Alice", 30)
fmt.Sprintf("result: %v", data)     // 返回字符串
fmt.Fprintf(w, "data: %v", data)    // 写入 Writer

// 格式化输入
fmt.Scanf("%d %s", &age, &name)
fmt.Sscanf("42 Alice", "%d %s", &age, &name)

// 常用动词
// %v   — 默认格式
// %+v  — 带字段名
// %#v  — Go 语法表示
// %T   — 类型名
// %d   — 十进制整数
// %x   — 十六进制
// %f   — 浮点数
// %s   — 字符串
// %q   — 带引号字符串
// %p   — 指针地址
// %t   — 布尔值
// %02d — 宽度2,前导零

2. 文件与操作系统

2.1 os 包

import "os"

// 文件操作
file, err := os.Open("data.txt")           // 只读打开
file, err := os.Create("output.txt")       // 创建/截断
file, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
file.Close()

// 快捷读写
data, err := os.ReadFile("data.txt")       // 读取整个文件
err := os.WriteFile("out.txt", data, 0644) // 写入整个文件

// 文件信息
info, _ := os.Stat("data.txt")
fmt.Println(info.Size(), info.Mode(), info.ModTime())

// 目录操作
entries, _ := os.ReadDir(".")              // 读取目录
os.Mkdir("subdir", 0755)                  // 创建目录
os.MkdirAll("a/b/c", 0755)               // 递归创建
os.Remove("file.txt")                     // 删除文件
os.RemoveAll("dir")                       // 递归删除

// 环境变量
home := os.Getenv("HOME")
os.Setenv("KEY", "value")
for _, env := range os.Environ() {
    fmt.Println(env)
}

// 命令行参数
args := os.Args // []string{程序名, 参数1, 参数2, ...}

// 退出
os.Exit(1)

2.2 filepath 包

import "path/filepath"

// 路径操作
filepath.Join("dir", "sub", "file.txt")    // "dir/sub/file.txt"(跨平台)
filepath.Ext("main.go")                    // ".go"
filepath.Base("/a/b/c.txt")               // "c.txt"
filepath.Dir("/a/b/c.txt")                // "/a/b"
filepath.IsAbs("/usr/local")              // true

// 遍历目录
filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
    if err != nil {
        return err
    }
    fmt.Println(path, d.IsDir())
    return nil
})

// 模式匹配
matches, _ := filepath.Glob("*.go")
matches, _ := filepath.Glob("src/**/*.go")

// 相对路径
rel, _ := filepath.Rel("/a/b", "/a/c/d")  // "../c/d"

// 绝对路径
abs, _ := filepath.Abs("./file.txt")

3. 网络与 HTTP

3.1 net/http 标准库

// HTTP 服务器
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!", r.URL.Query().Get("name"))
})

// Go 1.22+ 路由模式匹配
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    fmt.Fprintf(w, "User ID: %s", id)
})
mux.HandleFunc("POST /users", createUser)

log.Fatal(http.ListenAndServe(":8080", mux))

// HTTP 客户端
resp, err := http.Get("https://api.example.com/data")
if err != nil { log.Fatal(err) }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)

// 自定义请求
client := &http.Client{Timeout: 10 * time.Second}
req, _ := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(jsonData))
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)

3.2 net 包

// TCP 服务器
ln, _ := net.Listen("tcp", ":8080")
for {
    conn, _ := ln.Accept()
    go handleConn(conn)
}

// TCP 客户端
conn, _ := net.Dial("tcp", "localhost:8080")
conn.Write([]byte("hello"))
buf := make([]byte, 1024)
n, _ := conn.Read(buf)

// DNS 查询
ips, _ := net.LookupIP("example.com")
cname, _ := net.LookupCNAME("example.com")

// 解析地址
host, port, _ := net.SplitHostPort("example.com:8080")

4. JSON 处理

4.1 encoding/json

type User struct {
    Name  string `json:"name"`
    Email string `json:"email,omitempty"`
    Age   int    `json:"age"`
}

// 序列化
user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
bytes, _ := json.Marshal(user)
pretty, _ := json.MarshalIndent(user, "", "  ")

// 反序列化
var u User
json.Unmarshal([]byte(`{"name":"Bob","age":25}`), &u)

// 流式处理
enc := json.NewEncoder(w)
enc.Encode(user)

dec := json.NewDecoder(r)
for dec.More() {
    var u User
    dec.Decode(&u)
}

// 动态 JSON
var data map[string]any
json.Unmarshal(jsonBytes, &data)

// 自定义 JSON 编解码
func (t Time) MarshalJSON() ([]byte, error) {
    return json.Marshal(t.Format(time.RFC3339))
}

func (t *Time) UnmarshalJSON(b []byte) error {
    s := string(b)
    parsed, err := time.Parse(time.RFC3339, s)
    t.Time = parsed
    return err
}

5. 时间处理

5.1 time 包

// 当前时间
now := time.Now()

// 创建时间
t := time.Date(2024, 6, 15, 10, 30, 0, 0, time.Local)

// 格式化(Go 使用参考时间 Mon Jan 2 15:04:05 MST 2006)
fmt.Println(now.Format("2006-01-02 15:04:05"))    // 2024-06-15 10:30:00
fmt.Println(now.Format(time.RFC3339))               // 2024-06-15T10:30:00+08:00

// 解析
t, _ := time.Parse("2006-01-02", "2024-06-15")
t, _ := time.Parse(time.RFC3339, "2024-06-15T10:30:00+08:00")

// 时间运算
tomorrow := now.Add(24 * time.Hour)
yesterday := now.Add(-24 * time.Hour)
diff := tomorrow.Sub(now) // 24h0m0s

// 时间比较
now.Before(tomorrow)  // true
now.After(yesterday)  // true
now.Equal(otherTime)  // 精确比较

// 定时器
timer := time.NewTimer(5 * time.Second)
<-timer.C // 阻塞 5 秒

// 定期执行
ticker := time.NewTicker(1 * time.Second)
for t := range ticker.C {
    fmt.Println("Tick at", t)
}

// 延迟执行
time.AfterFunc(5*time.Second, func() {
    fmt.Println("5 seconds later")
})

6. Go 工具链

6.1 go test

// 单元测试(文件名 _test.go,函数名 TestXxx)
func TestAdd(t *testing.T) {
    result := Add(2, 3)
    if result != 5 {
        t.Errorf("Add(2, 3) = %d, want 5", result)
    }
}

// 表驱动测试
func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive", 2, 3, 5},
        {"negative", -1, -2, -3},
        {"zero", 0, 0, 0},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := Add(tt.a, tt.b); got != tt.expected {
                t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.expected)
            }
        })
    }
}
# 运行测试
go test ./...
go test -v ./...              # 详细输出
go test -run TestAdd ./...    # 运行指定测试
go test -count=1 ./...        # 禁用缓存

# 基准测试
go test -bench=. -benchmem    # 运行基准测试,显示内存分配

6.2 基准测试

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(2, 3)
    }
}

// 子基准测试
func BenchmarkJSON(b *testing.B) {
    data := User{Name: "Alice", Age: 30}
    b.Run("marshal", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            json.Marshal(data)
        }
    })
    b.Run("unmarshal", func(b *testing.B) {
        bytes, _ := json.Marshal(data)
        for i := 0; i < b.N; i++ {
            var u User
            json.Unmarshal(bytes, &u)
        }
    })
}

6.3 go vet

# 静态分析,检测常见错误
go vet ./...

# 检测内容:
# - Printf 格式字符串错误
# - 未使用的变量
# - 错误的结构体标签
# - 死锁
# - 不可达代码

6.4 go fmt

# 格式化代码
go fmt ./...
gofmt -w .   # 直接使用 gofmt
gofmt -d .   # 显示差异(不修改)

6.5 go doc

# 查看文档
go doc fmt.Println
go doc net/http.Handler
go doc -all fmt  # 查看包的全部文档

# 启动本地文档服务器
godoc -http=:6060

7. 构建标签与条件编译

7.1 构建标签

// 文件顶部添加构建标签(必须紧贴文件开头)
//go:build linux

// 或组合条件
//go:build linux && amd64
//go:build linux || darwin
//go:build !windows

// 示例:platform_linux.go
//go:build linux

package platform

func getOS() string {
    return "linux"
}
# 按标签构建
go build -tags "linux" .
go build -tags "debug,verbose" .

7.2 文件名约定

platform_linux.go     # 仅 Linux
platform_windows.go   # 仅 Windows
platform_darwin.go    # 仅 macOS
arch_amd64.go         # 仅 amd64
arch_arm64.go         # 仅 arm64

8. 交叉编译

# 编译 Linux 可执行文件(在 Windows/macOS 上)
GOOS=linux GOARCH=amd64 go build -o app-linux .

# 编译 Windows 可执行文件
GOOS=windows GOARCH=amd64 go build -o app.exe .

# 编译 ARM 可执行文件
GOOS=linux GOARCH=arm64 go build -o app-arm64 .

# 常见组合
# GOOS       GOARCH
# linux      amd64
# linux      arm64
# windows    amd64
# darwin     amd64
# darwin     arm64  (Apple Silicon)

9. cgo

cgo 允许 Go 调用 C 代码:

// #include <stdio.h>
// #include <stdlib.h>
//
// void say_hello(const char* name) {
//     printf("Hello, %s!\n", name);
// }
import "C"
import "unsafe"

func main() {
    name := C.CString("World")
    defer C.free(unsafe.Pointer(name))
    C.say_hello(name)
}

// 使用 C 库
// #cgo LDFLAGS: -lm
// #include <math.h>
import "C"

func main() {
    result := C.sqrt(144)
    fmt.Println(float64(result)) // 12
}

注意:cgo 会增加编译时间、影响交叉编译、带来性能开销。非必要不使用。

10. 其他工具

10.1 go generate

// 在源码中添加指令
//go:generate stringer -type=Status

type Status int

const (
    StatusUnknown Status = iota
    StatusActive
    StatusInactive
)
# 执行代码生成
go generate ./...

10.2 pprof 性能分析

import _ "net/http/pprof"

go func() {
    http.ListenAndServe(":6060", nil)
}()
# CPU 分析
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

# 内存分析
go tool pprof http://localhost:6060/debug/pprof/heap

# 交互式分析
(pprof) top 10
(pprof) web           # 生成调用图
(pprof) list funcName # 查看函数级分析

10.3 go tool trace

# 运行追踪
go test -trace=trace.out ./...
go tool trace trace.out
# 在浏览器中查看 goroutine 调度、GC、网络等事件