Skip to content

第11章 标准库与常用工具(io / json / http / time / log)

📚 学习目标:会用 Go 标准库完成日常 80% 的工程任务。


🎯 章节导读

Go 的一大魅力就是标准库强大

  • 一个 net/http 就能撑起一个 Web 服务
  • 一个 encoding/json 搞定 JSON 序列化
  • 一个 io 抽象优雅得让人感动

生活类比: Go 的标准库就像一个配齐了的厨房:刀、勺、锅、灶、烤箱…该有的全有。第三方库通常只是"调味品",主菜你已经能做了。


1️⃣ io:通用数据流抽象

1.1 io.Reader 和 io.Writer

整个 io 体系建立在两个最小接口上:

go
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

文件、网络、内存 buffer、HTTP body…全部实现了这两个接口。

go
// 复制任何 Reader 到任何 Writer
io.Copy(dst io.Writer, src io.Reader) (int64, error)

io.Copy(os.Stdout, file)        // 文件 → 标准输出
io.Copy(httpRespBody, fileBody) // 文件 → HTTP 响应
io.Copy(buf, httpRespBody)      // HTTP 响应 → buffer

这就是为什么说 Go 的 io 是"用最少的接口表达最多的能力"。


1.2 常用的 io 工具

go
// 读完整个 Reader(小心:大文件可能 OOM)
data, err := io.ReadAll(r)

// 写字符串
io.WriteString(w, "hello")

// 限制读取字节数
io.LimitReader(r, 1024)        // 最多读 1KB

// 多个 Reader 串联
io.MultiReader(r1, r2, r3)

// 同时写多个 Writer(如 stdout + 日志文件)
io.MultiWriter(os.Stdout, logFile)

2️⃣ os 与 file:操作文件系统

go
// 读文件(小文件)
data, err := os.ReadFile("a.txt")

// 写文件
os.WriteFile("a.txt", []byte("hello"), 0644)

// 打开文件流式读
f, _ := os.Open("a.txt")
defer f.Close()
buf := make([]byte, 1024)
n, _ := f.Read(buf)

// 创建/写入
f, _ := os.Create("b.txt")
defer f.Close()
fmt.Fprintln(f, "hello")

// 追加
f, _ := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

// 删除
os.Remove("a.txt")
os.RemoveAll("./tempdir")

// 创建目录
os.MkdirAll("./a/b/c", 0755)

os.Args 拿命令行参数;os.Getenv("X") 拿环境变量;os.Exit(1) 退出程序。


3️⃣ encoding/json:JSON 序列化

3.1 序列化

go
type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

u := User{"Alice", 30}
b, _ := json.Marshal(u)      // {"name":"Alice","age":30}

3.2 反序列化

go
var u User
err := json.Unmarshal([]byte(`{"name":"Alice","age":30}`), &u)

3.3 struct tag 高级用法

go
type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Password string `json:"-"`             // 不序列化
    Email    string `json:"email,omitempty"`// 空值时省略
    Age      int    `json:"age,string"`    // 用字符串编码("30")
}

3.4 处理任意 JSON

go
var any map[string]interface{}
json.Unmarshal(data, &any)

// 或用 json.RawMessage 延迟解析
type Wrap struct {
    Type string          `json:"type"`
    Data json.RawMessage `json:"data"`
}

推荐第三方库:json-iterator/go(性能更好)、sonic(字节跳动出品)。


4️⃣ net/http:内置 HTTP 服务器

4.1 启动一个服务器只要 5 行

go
package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, Go!")
    })
    http.ListenAndServe(":8080", nil)
}

访问 http://localhost:8080/ → "Hello, Go!"

这是 Go 让人惊艳的瞬间:没有任何第三方框架,几行代码就是一个生产级 HTTP 服务。


4.2 路由参数 + 不同方法

go
http.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        // 查询
        name := r.URL.Query().Get("name")
        fmt.Fprintf(w, "GET name=%s", name)
    case "POST":
        // 读 body
        var data map[string]string
        json.NewDecoder(r.Body).Decode(&data)
        fmt.Fprintf(w, "POST %v", data)
    default:
        http.Error(w, "method not allowed", 405)
    }
})

4.3 中间件模式

中间件就是接受 handler、返回 handler 的高阶函数:

go
func logger(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next(w, r)
        log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
    }
}

http.HandleFunc("/api", logger(myHandler))

可以"洋葱式"叠层:

go
http.HandleFunc("/api", auth(rateLimit(logger(myHandler))))

4.4 客户端请求

go
// GET
resp, err := http.Get("https://api.github.com")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)

// POST JSON
data, _ := json.Marshal(map[string]string{"name":"alice"})
resp, _ := http.Post("https://api.example.com/users", "application/json", bytes.NewReader(data))

// 自定义 client(控制超时、重试)
client := &http.Client{Timeout: 5 * time.Second}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer xxx")
resp, _ := client.Do(req)

5️⃣ time:时间操作

go
now := time.Now()                  // 当前时间
t := time.Unix(1700000000, 0)      // 时间戳转 time
ts := now.Unix()                   // time 转时间戳

// 格式化(必须用这个魔法时间)
t.Format("2006-01-02 15:04:05")    // → 2026-05-07 21:00:00
t.Format(time.RFC3339)             // → 2026-05-07T21:00:00Z

// 解析
time.Parse("2006-01-02", "2026-01-01")

// 计算
yesterday := now.Add(-24 * time.Hour)
diff := time.Since(start)          // 距离 start 的时长

// 定时
time.Sleep(2 * time.Second)
<-time.After(5 * time.Second)
ticker := time.NewTicker(1 * time.Second)

Go 的格式化用 2006-01-02 15:04:05 这个特殊时间,因为它从美国习惯排列正好是 01-02 03:04:05 PM 06。怪但好记。


6️⃣ log / log/slog:日志

6.1 标准 log

go
log.Println("info message")
log.Printf("user=%s action=%s", name, act)
log.Fatal("fatal error")        // 打日志后调 os.Exit(1)
log.Panic("panic")              // 打日志后 panic

6.2 Go 1.21+ 推荐:log/slog(结构化日志)

go
import "log/slog"

slog.Info("user login", "user", "alice", "ip", "1.2.3.4")
// 输出:time=... level=INFO msg="user login" user=alice ip=1.2.3.4

// JSON 格式
h := slog.NewJSONHandler(os.Stdout, nil)
slog.SetDefault(slog.New(h))
slog.Info("user login", "user", "alice")
// 输出:{"time":"...","level":"INFO","msg":"user login","user":"alice"}

生产环境推荐 slog(标准库)或 zap / zerolog(更高性能)。


7️⃣ flag:命令行参数

go
import "flag"

var port = flag.Int("port", 8080, "服务端口")
var host = flag.String("host", "0.0.0.0", "监听地址")
flag.Parse()

fmt.Printf("server on %s:%d\n", *host, *port)
bash
$ go run . -port 9000 -host 127.0.0.1
server on 127.0.0.1:9000

8️⃣ context:取消和超时(与并发结合)

go
// 创建带超时的 context
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

// HTTP 请求带 ctx
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := http.DefaultClient.Do(req)

// 自定义函数尊重 ctx
func work(ctx context.Context) error {
    select {
    case <-time.After(5 * time.Second):
        return nil
    case <-ctx.Done():
        return ctx.Err()  // context.DeadlineExceeded
    }
}

9️⃣ 其他常用包速览

用途例子
strings字符串处理strings.Contains, Split, Join, ToLower
strconv字符串和数字转换strconv.Atoi, Itoa, ParseFloat
sort排序sort.Ints, sort.Slice
bytes[]byte 处理(API 与 strings 类似)bytes.Buffer
bufio缓冲 IObufio.NewScanner(os.Stdin)
regexp正则regexp.MustCompile(...)
path/filepath文件路径filepath.Join, filepath.Walk
crypto/sha256哈希sha256.Sum256(data)
encoding/base64base64 编码base64.StdEncoding.EncodeToString

📚 本章小结

任务推荐包
文件读写osio
JSONencoding/json
HTTP 服务net/http
HTTP 客户端net/http
时间time
日志log/slog(推荐)
命令行参数flag
取消/超时context
字符串stringsstrconvregexp

📁 本章配套

进入第12章 →