目录

Go 标准库

Go 的标准库功能强大且全面,涵盖了网络、系统、文本处理等常见需求。“batteries included” 是 Go 的设计哲学之一——大多数场景无需引入第三方库。本篇介绍最常用的标准库包及其典型用法。

https://img.zhaojq.top/20260729163102292.png
标准库全景

net/http:HTTP 服务器

net/http 包可以轻松创建 HTTP 服务器。

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

// 处理首页请求
func homeHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "欢迎使用 Go HTTP 服务器!\n")
	fmt.Fprintf(w, "请求方法: %s, 路径: %s\n", r.Method, r.URL.Path)
}

// 处理 JSON API
func apiHandler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{
		"status":  "ok",
		"message": "Hello, API!",
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(data)
}

// 处理用户信息(带路径参数)
func userHandler(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get("name")
	if name == "" {
		name = "匿名"
	}
	fmt.Fprintf(w, "你好, %s!\n", name)
}

func main() {
	http.HandleFunc("/", homeHandler)
	http.HandleFunc("/api", apiHandler)
	http.HandleFunc("/user", userHandler)

	fmt.Println("服务器启动在 :8080")
	http.ListenAndServe(":8080", nil)
}

http.HandleFunc 注册路由处理函数,http.ListenAndServe 启动监听。http.ResponseWriter 用于写响应,*http.Request 包含请求信息。

net/http:HTTP 客户端

net/http 同样提供了 HTTP 客户端功能。

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

func main() {
	// === GET 请求 ===
	resp, err := http.Get("https://httpbin.org/get")
	if err != nil {
		fmt.Println("请求失败:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Printf("GET 状态码: %d\n", resp.StatusCode)
	fmt.Printf("GET 响应: %s\n\n", string(body[:200]))

	// === POST 请求 ===
	jsonData := `{"name": "张三", "age": 28}`
	resp2, err := http.Post("https://httpbin.org/post", "application/json",
		strings.NewReader(jsonData))
	if err != nil {
		fmt.Println("POST 失败:", err)
		return
	}
	defer resp2.Body.Close()

	body2, _ := io.ReadAll(resp2.Body)
	fmt.Printf("POST 状态码: %d\n", resp2.StatusCode)
	fmt.Printf("POST 响应: %s\n\n", string(body2[:200]))

	// === 使用自定义 Client(带超时) ===
	client := &http.Client{
		Timeout: 5 * time.Second,
	}

	req, _ := http.NewRequest("GET", "https://httpbin.org/delay/1", nil)
	req.Header.Set("Accept", "application/json")

	resp3, err := client.Do(req)
	if err != nil {
		fmt.Println("请求失败:", err)
		return
	}
	defer resp3.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp3.Body).Decode(&result)
	fmt.Printf("自定义 Client 响应: %v\n", result["url"])
}

推荐使用自定义的 http.Client 而非全局的 http.Get/http.Post,因为可以设置超时和其他配置。

context 包

context 包用于在 goroutine 之间传递截止时间、取消信号和请求范围的值。

package main

import (
	"context"
	"fmt"
	"time"
)

// 模拟一个耗时操作
func slowOperation(ctx context.Context) (string, error) {
	select {
	case <-time.After(2 * time.Second):
		return "操作完成", nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

func main() {
	// === 超时控制 ===
	fmt.Println("--- 超时控制 ---")
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
	defer cancel()

	result, err := slowOperation(ctx)
	if err != nil {
		fmt.Println("错误:", err) // 超时错误
	} else {
		fmt.Println("结果:", result)
	}

	// === 值传递 ===
	fmt.Println("\n--- 值传递 ---")
	ctx2 := context.WithValue(context.Background(), "userID", 42)
	ctx3 := context.WithValue(ctx2, "role", "admin")

	fmt.Println("userID:", ctx3.Value("userID"))
	fmt.Println("role:", ctx3.Value("role"))

	// === 取消传播 ===
	fmt.Println("\n--- 取消传播 ---")
	parent, parentCancel := context.WithCancel(context.Background())

	child1, child1Cancel := context.WithCancel(parent)
	defer child1Cancel()

	child2, child2Cancel := context.WithCancel(parent)
	defer child2Cancel()

	go func() {
		<-child1.Done()
		fmt.Println("child1 被取消")
	}()

	go func() {
		<-child2.Done()
		fmt.Println("child2 被取消")
	}()

	parentCancel() // 取消 parent,child1 和 child2 也会被级联取消
	time.Sleep(100 * time.Millisecond)
}

context.Background() 创建根 context。WithTimeout 设置超时,WithCancel 手动取消,WithValue 传递键值对。context 是不可变的,派生操作会返回新的 context。

time 包

time 包提供时间和日期的处理功能。

package main

import (
	"fmt"
	"time"
)

func main() {
	// === Time 基本操作 ===
	now := time.Now()
	fmt.Printf("当前时间: %s\n", now.Format("2006-01-02 15:04:05"))

	// 解析时间
	t, _ := time.Parse("2006-01-02", "2024-06-15")
	fmt.Printf("解析时间: %s\n", t.Format("2006年01月02日"))

	// 时间计算
	tomorrow := now.AddDate(0, 0, 1)
	fmt.Printf("明天: %s\n", tomorrow.Format("2006-01-02"))

	// 时间差
	diff := tomorrow.Sub(now)
	fmt.Printf("时间差: %v\n", diff)

	// === Duration ===
	fmt.Println("\n--- Duration ---")
	d := 2*time.Hour + 30*time.Minute
	fmt.Printf("Duration: %v = %v 秒\n", d, d.Seconds())

	// === Ticker(定时器) ===
	fmt.Println("\n--- Ticker ---")
	ticker := time.NewTicker(100 * time.Millisecond)
	done := make(chan bool)

	go func() {
		count := 0
		for {
			select {
			case <-ticker.C:
				count++
				fmt.Printf("Tick %d\n", count)
				if count >= 3 {
					ticker.Stop()
					done <- true
					return
				}
			}
		}
	}()

	<-done
	fmt.Println("Ticker 停止")

	// === Timer(一次性定时器) ===
	fmt.Println("\n--- Timer ---")
	timer := time.NewTimer(200 * time.Millisecond)
	<-timer.C
	fmt.Println("Timer 到期")
}

Go 的时间格式化使用固定的参考时间 2006-01-02 15:04:05(对应 1/2 3:04:05 ‘06 -0700)。Duration 表示时间间隔,Ticker 周期性触发,Timer 一次性触发。

log 包

log 包提供基本的日志功能。

package main

import (
	"log"
	"os"
)

func main() {
	// 基本日志输出
	log.Println("这是一条普通日志")
	log.Printf("格式化日志: 用户 %s 已登录", "张三")

	// 自定义 logger
	file, err := os.OpenFile("/tmp/go-demo/app.log",
		os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatal("打开日志文件失败:", err)
	}
	defer file.Close()

	// 同时输出到文件和控制台
	// 这里简化为只输出到文件
	logger := log.New(file, "[APP] ", log.Ldate|log.Ltime|log.Lshortfile)
	logger.Println("这条日志写入文件")
	logger.Printf("用户操作: %s", "查询数据")

	// 日志级别模拟
	infoLog := log.New(os.Stdout, "[INFO] ", log.LstdFlags)
	warnLog := log.New(os.Stdout, "[WARN] ", log.LstdFlags)
	errorLog := log.New(os.Stderr, "[ERROR] ", log.LstdFlags|log.Lshortfile)

	infoLog.Println("服务启动成功")
	warnLog.Println("内存使用率较高")
	errorLog.Println("数据库连接失败")
}

log.Fatal 输出日志后调用 os.Exit(1) 退出程序。log.Panic 输出日志后调用 panic。生产环境建议使用 slog(Go 1.21+)或第三方日志库如 zap

fmt 包

fmt 包提供格式化 I/O 功能。

package main

import "fmt"

func main() {
	// === Print 系列 ===
	fmt.Print("无换行 ")
	fmt.Println("有换行")

	// === Sprintf(返回字符串) ===
	name := "张三"
	age := 28
	s := fmt.Sprintf("姓名: %s, 年龄: %d", name, age)
	fmt.Println(s)

	// === Errorf(返回 error) ===
	err := fmt.Errorf("用户 %s 年龄 %d 不合法", name, -1)
	fmt.Println("错误:", err)

	// === 常用格式化动词 ===
	fmt.Println("\n--- 格式化示例 ---")
	fmt.Printf("整数: %d\n", 42)
	fmt.Printf("浮点: %.2f\n", 3.14159)
	fmt.Printf("字符串: %s\n", "hello")
	fmt.Printf("布尔: %t\n", true)
	fmt.Printf("十六进制: %x\n", 255)
	fmt.Printf("指针: %p\n", &name)
	fmt.Printf("通用: %v\n", []int{1, 2, 3})
	fmt.Printf("结构体: %+v\n", struct{ X int }{X: 10})
	fmt.Printf("类型: %T\n", 42)
	fmt.Printf("宽度: |%10s|\n", "hi")
	fmt.Printf("左对齐: |%-10s|\n", "hi")
	fmt.Printf("补零: |%05d|\n", 42)
}

strings 和 bytes 包

strings 处理字符串,bytes 处理字节切片,API 基本对称。

package main

import (
	"bytes"
	"fmt"
	"strings"
)

func main() {
	s := "  Hello, Go World!  "

	// 大小写
	fmt.Println("大写:", strings.ToUpper("hello"))
	fmt.Println("小写:", strings.ToLower("HELLO"))

	// 查找与判断
	fmt.Println("包含:", strings.Contains(s, "Go"))
	fmt.Println("前缀:", strings.HasPrefix(strings.TrimSpace(s), "Hello"))
	fmt.Println("后缀:", strings.HasSuffix(strings.TrimSpace(s), "!"))

	// 分割与连接
	parts := strings.Split("a,b,c,d", ",")
	fmt.Println("分割:", parts)
	fmt.Println("连接:", strings.Join(parts, " | "))

	// 替换与修剪
	fmt.Println("替换:", strings.Replace("hello world", "world", "Go", 1))
	fmt.Println("修剪:", strings.TrimSpace(s))
	fmt.Println("修剪字符:", strings.Trim("###title###", "#"))

	// Builder(高效拼接)
	var builder strings.Builder
	for i := 0; i < 5; i++ {
		fmt.Fprintf(&builder, "item-%d ", i)
	}
	fmt.Println("Builder:", builder.String())

	// bytes.Buffer(字节缓冲)
	var buf bytes.Buffer
	buf.WriteString("Hello ")
	buf.WriteString("World")
	fmt.Println("Buffer:", buf.String())
	fmt.Println("Buffer 字节:", buf.Bytes())
}

os 包

os 包提供操作系统相关的功能。

package main

import (
	"fmt"
	"os"
)

func main() {
	// 环境变量
	os.Setenv("APP_ENV", "production")
	fmt.Println("APP_ENV:", os.Getenv("APP_ENV"))
	fmt.Println("HOME:", os.Getenv("HOME"))

	// 命令行参数
	fmt.Println("\n程序名:", os.Args[0])
	fmt.Printf("参数数量: %d\n", len(os.Args))

	// 进程信息
	fmt.Println("\n进程ID:", os.Getpid())
	fmt.Println("父进程ID:", os.Getppid())
	fmt.Println("工作目录:", func() string {
		dir, _ := os.Getwd()
		return dir
	}())

	// 临时目录
	fmt.Println("临时目录:", os.TempDir())

	// 退出(注释掉避免程序退出)
	// os.Exit(0)
}

总结

Go 标准库覆盖了日常开发的大部分需求。net/http 提供 HTTP 服务器和客户端;context 管理 goroutine 的超时和取消;time 处理时间和日期;log 提供日志功能;fmt 负责格式化 I/O;strings/bytes 处理文本和字节数据;os 与操作系统交互。Go 标准库的设计简洁一致,掌握这些核心包可以应对绝大多数开发场景,减少对外部依赖的需要。