主题
第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") // 打日志后 panic6.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:90008️⃣ 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 | 缓冲 IO | bufio.NewScanner(os.Stdin) |
regexp | 正则 | regexp.MustCompile(...) |
path/filepath | 文件路径 | filepath.Join, filepath.Walk |
crypto/sha256 | 哈希 | sha256.Sum256(data) |
encoding/base64 | base64 编码 | base64.StdEncoding.EncodeToString |
📚 本章小结
| 任务 | 推荐包 |
|---|---|
| 文件读写 | os、io |
| JSON | encoding/json |
| HTTP 服务 | net/http |
| HTTP 客户端 | net/http |
| 时间 | time |
| 日志 | log/slog(推荐) |
| 命令行参数 | flag |
| 取消/超时 | context |
| 字符串 | strings、strconv、regexp |
📁 本章配套
- 📄 examples/:每个标准库一个迷你示例
- 🌐 demo.html:交互演示 HTTP / JSON / time
- ❓ interview.md:标准库高频面试题
- 🖼 diagrams/:标准库全景图
进入第12章 →