第 17 章 / 共 20 章
标准库速览
fmt / strings / time / json / context / sort / slog 等
Go 标准库覆盖网络、IO、文本、加密、压缩、并发、模板等绝大多数日常需求。下面挑实战中最常用的几个包过一遍——掌握它们能让你 80% 的功能不依赖三方库。
fmt:格式化 I/O
Printf / Sprintf / Fprintf / Errorf 是同一套占位符系统。常用占位符:
%v 默认格式
%+v 结构体带字段名
%#v Go 语法字面量
%T 类型
%d 十进制整数
%b %o %x %X 二/八/十六进制
%f %e %g 浮点数
%.2f 保留 2 位小数
%s 字符串
%q 带引号字符串(自动转义)
%c rune 字符
%U Unicode 码点(U+4E2D)
%t 布尔
%p 指针地址
%w 包装 error(仅 fmt.Errorf)
宽度对齐:%-8s 左对齐 8 字符;%8d 右对齐 8 字符package main
import (
"errors"
"fmt"
)
func main() {
name, age, score := "Alice", 30, 95.5
fmt.Printf("%-8s %3d %.2f\n", name, age, score)
s := fmt.Sprintf("hello %s", name)
fmt.Println(s)
orig := errors.New("disk full")
err := fmt.Errorf("save %q: %w", "out.txt", orig) // 用 %w 包装
fmt.Println(err)
fmt.Println(errors.Is(err, orig)) // true
}strings / bytes
strings 操作不可变字符串;bytes 提供等价 API 但操作 []byte。两者函数几乎一一对应。
package main
import (
"fmt"
"strings"
)
func main() {
s := " Hello Go "
fmt.Println(strings.Contains(s, "Go")) // true
fmt.Println(strings.HasPrefix("v1.22.0", "v1.")) // true
fmt.Println(strings.Split("a,b,c", ",")) // [a b c]
fmt.Println(strings.Join([]string{"a", "b"}, "/")) // a/b
fmt.Println(strings.ReplaceAll("a\r\nb", "\r\n", "\n")) // a\nb
fmt.Println(strings.TrimSpace(s)) // Hello Go
fmt.Println(strings.Fields(" hello go ")) // [hello go]
fmt.Println(strings.EqualFold("Go", "go")) // true
var b strings.Builder
for i := 0; i < 100; i++ {
b.WriteString("x")
}
fmt.Println(len(b.String())) // 100
}strconv:字符串 ⇄ 数字
package main
import (
"fmt"
"strconv"
)
func main() {
n, err := strconv.Atoi("42") // string -> int
fmt.Println(n, err)
s := strconv.Itoa(42) // int -> string
fmt.Println(s)
f, _ := strconv.ParseFloat("3.14", 64) // string -> float64
s2 := strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
fmt.Println(f, s2)
b, _ := strconv.ParseBool("true")
fmt.Println(b)
q := strconv.Quote(`he said "hi"`) // "he said \"hi\""
fmt.Println(q)
}time:时间与时长
time.Time 表示一个绝对时刻,time.Duration 是 int64 纳秒。Go 的格式化模板用一个固定的“魔法时间” 2006-01-02 15:04:05 ——01/02 03:04:05 PM '06 -0700 也对应着 1/2/3/4/5/6/7。
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now.Format("2006-01-02 15:04:05"))
fmt.Println(now.Format(time.RFC3339))
t, err := time.Parse(time.RFC3339, "2026-05-12T08:00:00Z")
fmt.Println(t, err)
loc, _ := time.LoadLocation("Asia/Shanghai")
fmt.Println(t.In(loc))
d := 2*time.Hour + 30*time.Minute
future := now.Add(d)
fmt.Println(future.Sub(now)) // 2h30m0s
fmt.Println(now.Unix(), now.UnixMilli(), now.UnixNano())
}定时器与节流
package main
import (
"fmt"
"time"
)
func main() {
// 延时
time.Sleep(100 * time.Millisecond)
// 一次性触发
<-time.After(100 * time.Millisecond)
// 周期性触发
ticker := time.NewTicker(200 * time.Millisecond)
defer ticker.Stop()
stop := time.After(700 * time.Millisecond)
for {
select {
case t := <-ticker.C:
fmt.Println("tick", t.Format("15:04:05.000"))
case <-stop:
return
}
}
}encoding/json
Marshal / Unmarshal 处理内存中的整块 JSON;NewEncoder / NewDecoder 适合流式(HTTP body、大文件)。结构体 tag 控制字段名、可选字段、忽略。
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"` // 空值省略
Password string `json:"-"` // 永不输出
Created time.Time `json:"created_at"`
}
func main() {
b, _ := json.MarshalIndent(User{1, "Alice", "", "pw", time.Now()}, "", " ")
fmt.Println(string(b))
var u User
_ = json.Unmarshal(b, &u)
fmt.Println(u.Name)
// 流式:处理超大 JSON 数组
src := `[{"id":1,"name":"a","created_at":"2026-05-12T00:00:00Z"},{"id":2,"name":"b","created_at":"2026-05-12T00:00:00Z"}]`
dec := json.NewDecoder(strings.NewReader(src))
dec.Token() // 跳过开头的 [
for dec.More() {
var u User
if err := dec.Decode(&u); err != nil {
break
}
fmt.Println(u.ID, u.Name)
}
}context:取消、超时、传值
context 在调用链中传递取消信号、超时与请求级数据,是所有库公认的“函数第一个参数”。规则:父 context 取消时,所有派生子 context 一并取消。
package main
import (
"context"
"errors"
"fmt"
"log"
"net/http"
"time"
)
type traceKey struct{}
func main() {
ctx := context.Background() // 根
ctx, cancel := context.WithTimeout(ctx, 2*time.Second) // 超时
defer cancel() // 必须 defer cancel
req, _ := http.NewRequestWithContext(ctx, "GET", "https://example.com", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
log.Println("timeout")
} else {
log.Println("err:", err)
}
} else {
resp.Body.Close()
}
// 传请求级数据(只放贯穿调用链的元数据如 trace id)
ctx = context.WithValue(ctx, traceKey{}, "req-123")
trace := ctx.Value(traceKey{}).(string)
fmt.Println("trace:", trace)
}errors:包装、判断、拆包
package main
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("not found")
type User struct{ ID int }
func Get(id int) (*User, error) {
if id == 0 {
return nil, fmt.Errorf("get(%d): %w", id, ErrNotFound)
}
return &User{ID: id}, nil
}
func main() {
_, err := Get(0)
if errors.Is(err, ErrNotFound) {
fmt.Println("not found")
}
// 多错误聚合(Go 1.20+)
joined := errors.Join(errors.New("a"), errors.New("b"))
fmt.Println(joined)
}sort / slices / maps
Go 1.21+ 加入泛型化的 slices 和 maps 包,比旧 sort 包好用很多。
package main
import (
"fmt"
"maps"
"slices"
"sort"
"strings"
)
type User struct {
Name string
Age int
}
func main() {
nums := []int{3, 1, 4, 1, 5, 9}
slices.Sort(nums)
fmt.Println(nums)
users := []User{{"Bob", 30}, {"Alice", 25}}
slices.SortFunc(users, func(a, b User) int {
return strings.Compare(a.Name, b.Name)
})
fmt.Println(users)
idx, ok := slices.BinarySearch(nums, 4)
fmt.Println(idx, ok)
fmt.Println(slices.Contains(nums, 5), slices.Max(nums))
fmt.Println(slices.Compact(slices.Clone(nums))) // 去除相邻重复
m := map[string]int{"a": 1, "b": 2}
keys := slices.Sorted(maps.Keys(m))
fmt.Println(keys)
fmt.Println(maps.Clone(m))
// 旧式 sort 仍可用
sort.Slice(users, func(i, j int) bool { return users[i].Age < users[j].Age })
}regexp
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`(\w+)@(\w+\.\w+)`)
fmt.Println(re.MatchString("a@b.c")) // true
fmt.Println(re.FindStringSubmatch("a@b.c")) // [a@b.c a b.c]
fmt.Println(re.ReplaceAllString("a@b.c", "$1 at $2")) // a at b.c
// 编译失败处理
if _, err := regexp.Compile(`(`); err != nil {
fmt.Println("bad pattern:", err)
}
}log/slog:结构化日志(Go 1.21+)
新版结构化日志库。支持 JSON / Text handler、属性分组、级别控制,是替换 logrus / zap 的官方选项。
package main
import (
"errors"
"log/slog"
"os"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
slog.SetDefault(logger)
slog.Info("user login",
"user_id", 42,
"ip", "127.0.0.1",
)
slog.Error("save failed", "err", errors.New("disk full"))
}其它高频包
- encoding/base64 · encoding/hex · encoding/csv
- crypto/sha256 · crypto/hmac · crypto/rand
- compress/gzip · archive/zip · archive/tar
- net/url:URL 解析与查询字符串
- os/exec:执行外部命令
- os/signal:监听 SIGINT/SIGTERM 实现优雅停机
- runtime/pprof · net/http/pprof:性能剖析
- embed:把静态资源编进二进制(//go:embed)