Appearance
标准库包
1. 概述
Go 语言的标准库是 Go 语言生态系统的核心组成部分,它提供了丰富的功能模块,涵盖了网络、文件操作、编码、并发等多个领域。标准库包经过精心设计和优化,具有高性能、可靠性和跨平台特性。本知识点承接版本控制,深入讲解 Go 语言标准库的结构、使用方法和最佳实践,帮助开发者充分利用标准库的强大功能。
2. 基本概念
2.1 语法
标准库包的导入
go
// 导入单个包
import "fmt"
// 导入多个包
import (
"fmt"
"net/http"
"encoding/json"
)
// 导入并使用别名
import (
"fmt"
http "net/http"
json "encoding/json"
)
// 空白导入(仅执行包的 init 函数)
import (
_ "net/http/pprof"
)常用标准库包示例
go
// fmt 包:格式化输入输出
import "fmt"
func main() {
fmt.Println("Hello, World!")
fmt.Printf("Name: %s, Age: %d\n", "John", 30)
}
// net/http 包:HTTP 客户端和服务器
import "net/http"
func main() {
// 启动 HTTP 服务器
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, HTTP!"))
})
http.ListenAndServe(":8080", nil)
}
// encoding/json 包:JSON 编解码
import "encoding/json"
func main() {
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
// 编码为 JSON
p := Person{Name: "John", Age: 30}
data, err := json.Marshal(p)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(string(data))
// 解码 JSON
var p2 Person
err = json.Unmarshal(data, &p2)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(p2.Name, p2.Age)
}2.2 语义
- 标准库:Go 语言官方提供的包集合,包含在 Go 安装包中
- 包路径:标准库包的导入路径,如 "fmt"、"net/http" 等
- 核心包:提供基础功能的包,如 fmt、strconv、errors 等
- 工具包:提供特定功能的包,如 net/http、encoding/json、io 等
- 平台包:与操作系统相关的包,如 os、syscall 等
- 并发包:提供并发编程支持的包,如 sync、context 等
2.3 规范
- 包的使用:优先使用标准库包,避免重复造轮子
- 导入规范:按照标准库、第三方库、本地库的顺序导入
- 错误处理:正确处理标准库返回的错误
- 性能考虑:了解标准库的性能特性,避免性能陷阱
- 版本兼容性:注意不同 Go 版本中标准库的变化
- 最佳实践:遵循标准库的设计模式和使用约定
3. 原理深度解析
3.1 标准库的结构
- 核心层:提供基础功能,如 fmt、strconv、errors、reflect 等
- 工具层:提供通用工具,如 encoding、io、net、os 等
- 平台层:提供平台相关功能,如 syscall、runtime 等
- 扩展层:提供高级功能,如 database/sql、html/template 等
3.2 标准库的设计理念
- 简洁性:API 设计简洁明了,易于使用
- 一致性:相似功能的 API 设计保持一致
- 高性能:底层实现经过优化,性能优异
- 可靠性:经过充分测试,稳定可靠
- 可扩展性:设计上支持扩展,如接口设计
3.3 标准库的实现机制
- 接口抽象:使用接口定义行为,实现多态
- 结构体封装:使用结构体封装数据和方法
- 函数式编程:支持函数作为参数和返回值
- 错误处理:使用 error 接口统一错误处理
- 并发支持:内置并发原语和工具
4. 常见错误与踩坑点
4.1 错误表现:HTTP 服务器未关闭
产生原因:启动 HTTP 服务器后未正确关闭,导致资源泄漏 解决方案:使用 context 控制服务器生命周期,或使用 http.Server 结构体并调用 Close 方法
4.2 错误表现:JSON 编解码失败
产生原因:结构体字段未导出(首字母小写),或类型不支持 JSON 编解码 解决方案:确保结构体字段首字母大写,或使用 json 标签指定字段名
4.3 错误表现:文件操作未关闭
产生原因:打开文件后未调用 Close 方法,导致文件句柄泄漏 解决方案:使用 defer 语句确保文件关闭
4.4 错误表现:并发安全问题
产生原因:多个 goroutine 同时访问共享资源,未加锁保护 解决方案:使用 sync 包中的互斥锁或其他同步原语
4.5 错误表现:超时处理不当
产生原因:网络请求或其他操作未设置超时,导致程序阻塞 解决方案:使用 context 包设置超时,或使用带有超时参数的函数
4.6 错误表现:内存泄漏
产生原因:未释放不再使用的资源,如 goroutine、通道、内存等 解决方案:确保所有资源都能正确释放,使用 defer 语句,避免 goroutine 泄漏
5. 常见应用场景
5.1 场景描述:HTTP 服务器
使用方法:使用 net/http 包创建 HTTP 服务器 示例代码:
go
package main
import (
"fmt"
"net/http"
)
func main() {
// 注册路由
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, HTTP!"))
})
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"message": "Hello, API!"}`))
})
// 启动服务器
fmt.Println("Server running on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}5.2 场景描述:JSON 编解码
使用方法:使用 encoding/json 包进行 JSON 编解码 示例代码:
go
package main
import (
"encoding/json"
"fmt"
)
// 定义结构体
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age,omitempty"`
IsActive bool `json:"is_active"`
}
func main() {
// 编码为 JSON
user := User{
ID: 1,
Name: "John Doe",
Email: "john@example.com",
IsActive: true,
}
data, err := json.Marshal(user)
if err != nil {
fmt.Println("Error encoding JSON:", err)
return
}
fmt.Println("Encoded JSON:", string(data))
// 解码 JSON
var decodedUser User
err = json.Unmarshal(data, &decodedUser)
if err != nil {
fmt.Println("Error decoding JSON:", err)
return
}
fmt.Println("Decoded User:", decodedUser)
}5.3 场景描述:文件操作
使用方法:使用 os 和 io 包进行文件操作 示例代码:
go
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
// 创建文件
file, err := os.Create("example.txt")
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer file.Close()
// 写入文件
data := []byte("Hello, File!")
_, err = file.Write(data)
if err != nil {
fmt.Println("Error writing to file:", err)
return
}
// 读取文件
data, err = ioutil.ReadFile("example.txt")
if err != nil {
fmt.Println("Error reading file:", err)
return
}
fmt.Println("File content:", string(data))
// 删除文件
err = os.Remove("example.txt")
if err != nil {
fmt.Println("Error deleting file:", err)
return
}
fmt.Println("File deleted successfully")
}5.4 场景描述:并发编程
使用方法:使用 sync 和 context 包进行并发编程 示例代码:
go
package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
// 创建上下文
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 创建等待组
var wg sync.WaitGroup
// 启动多个 goroutine
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
select {
case <-ctx.Done():
fmt.Printf("Goroutine %d: Context cancelled\n", id)
return
case <-time.After(time.Duration(id) * time.Second):
fmt.Printf("Goroutine %d: Completed\n", id)
}
}(i)
}
// 等待所有 goroutine 完成
wg.Wait()
fmt.Println("All goroutines completed")
}5.5 场景描述:网络客户端
使用方法:使用 net/http 包创建 HTTP 客户端 示例代码:
go
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
)
func main() {
// 创建 HTTP 客户端
client := &http.Client{
Timeout: 10 * time.Second,
}
// 发送 GET 请求
resp, err := client.Get("https://api.github.com/users/golang")
if err != nil {
fmt.Println("Error sending request:", err)
return
}
defer resp.Body.Close()
// 读取响应
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Println("Response status:", resp.Status)
fmt.Println("Response body:", string(data))
}6. 企业级进阶应用场景
6.1 场景描述:RESTful API 服务
使用方法:使用标准库构建完整的 RESTful API 服务 示例代码:
go
package main
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
)
// 数据模型
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
}
// 模拟数据库
var products = []Product{
{ID: 1, Name: "Product 1", Price: 10.99},
{ID: 2, Name: "Product 2", Price: 19.99},
{ID: 3, Name: "Product 3", Price: 5.99},
}
// 处理函数
func getProducts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(products)
}
func getProduct(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Path[len("/products/"):]
id, err := strconv.Atoi(idStr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "Invalid product ID"})
return
}
for _, p := range products {
if p.ID == id {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(p)
return
}
}
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(map[string]string{"error": "Product not found"})
}
func createProduct(w http.ResponseWriter, r *http.Request) {
var product Product
if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "Invalid request body"})
return
}
// 生成 ID
product.ID = len(products) + 1
products = append(products, product)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(product)
}
func main() {
// 注册路由
http.HandleFunc("/products", getProducts)
http.HandleFunc("/products/", getProduct)
http.HandleFunc("/products/create", createProduct)
// 启动服务器
fmt.Println("Server running on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}6.2 场景描述:文件服务器
使用方法:使用标准库构建文件服务器 示例代码:
go
package main
import (
"fmt"
"net/http"
"os"
"path/filepath"
)
// 自定义文件服务器
func fileServer() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 安全检查,防止路径遍历攻击
path := filepath.Join("./static", r.URL.Path)
if filepath.Dir(path) != "./static" {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("Access denied"))
return
}
// 检查文件是否存在
if _, err := os.Stat(path); os.IsNotExist(err) {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("File not found"))
return
}
// 提供文件
http.ServeFile(w, r, path)
})
}
func main() {
// 创建静态目录
if err := os.MkdirAll("./static", 0755); err != nil {
fmt.Println("Error creating static directory:", err)
return
}
// 创建测试文件
testFile, err := os.Create("./static/test.txt")
if err != nil {
fmt.Println("Error creating test file:", err)
return
}
testFile.WriteString("Hello from static file!")
testFile.Close()
// 注册路由
http.Handle("/static/", http.StripPrefix("/static/", fileServer()))
// 启动服务器
fmt.Println("File server running on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}6.3 场景描述:并发任务处理
使用方法:使用标准库处理并发任务 示例代码:
go
package main
import (
"context"
"fmt"
"sync"
"time"
)
// 任务函数
type Task func() error
// 工作池
type WorkerPool struct {
ctx context.Context
cancel context.CancelFunc
taskChan chan Task
workerWg sync.WaitGroup
resultChan chan error
}
// 创建工作池
func NewWorkerPool(size int) *WorkerPool {
ctx, cancel := context.WithCancel(context.Background())
pool := &WorkerPool{
ctx: ctx,
cancel: cancel,
taskChan: make(chan Task, 100),
resultChan: make(chan error, 100),
}
// 启动工作协程
for i := 0; i < size; i++ {
pool.workerWg.Add(1)
go pool.worker(i)
}
return pool
}
// 工作协程
func (p *WorkerPool) worker(id int) {
defer p.workerWg.Done()
for {
select {
case <-p.ctx.Done():
return
case task, ok := <-p.taskChan:
if !ok {
return
}
if err := task(); err != nil {
p.resultChan <- err
} else {
p.resultChan <- nil
}
}
}
}
// 添加任务
func (p *WorkerPool) AddTask(task Task) {
p.taskChan <- task
}
// 关闭工作池
func (p *WorkerPool) Close() []error {
close(p.taskChan)
p.workerWg.Wait()
close(p.resultChan)
// 收集结果
var errors []error
for err := range p.resultChan {
if err != nil {
errors = append(errors, err)
}
}
p.cancel()
return errors
}
func main() {
// 创建工作池
pool := NewWorkerPool(5)
// 添加任务
for i := 1; i <= 10; i++ {
taskID := i
pool.AddTask(func() error {
time.Sleep(time.Duration(taskID) * 100 * time.Millisecond)
fmt.Printf("Task %d completed\n", taskID)
return nil
})
}
// 关闭工作池并收集结果
errors := pool.Close()
if len(errors) > 0 {
fmt.Println("Errors:", errors)
} else {
fmt.Println("All tasks completed successfully")
}
}6.4 场景描述:配置管理
使用方法:使用标准库管理配置 示例代码:
go
package main
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)
// 配置结构
type Config struct {
Server ServerConfig `json:"server"`
Database DatabaseConfig `json:"database"`
Log LogConfig `json:"log"`
}
type ServerConfig struct {
Port int `json:"port"`
Host string `json:"host"`
ReadTimeout int `json:"read_timeout"`
WriteTimeout int `json:"write_timeout"`
}
type DatabaseConfig struct {
DSN string `json:"dsn"`
MaxIdleConns int `json:"max_idle_conns"`
MaxOpenConns int `json:"max_open_conns"`
ConnMaxLifetime int `json:"conn_max_lifetime"`
}
type LogConfig struct {
Level string `json:"level"`
Format string `json:"format"`
File string `json:"file"`
}
// 加载配置
func LoadConfig(configPath string) (*Config, error) {
// 读取配置文件
data, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("error reading config file: %w", err)
}
// 解析配置
var config Config
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("error unmarshaling config: %w", err)
}
return &config, nil
}
// 保存配置
func SaveConfig(config *Config, configPath string) error {
// 确保目录存在
dir := filepath.Dir(configPath)
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("error creating config directory: %w", err)
}
// 编码配置
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
return fmt.Errorf("error marshaling config: %w", err)
}
// 写入文件
if err := os.WriteFile(configPath, data, 0644); err != nil {
return fmt.Errorf("error writing config file: %w", err)
}
return nil
}
func main() {
// 配置路径
configPath := "./config.json"
// 创建默认配置
defaultConfig := &Config{
Server: ServerConfig{
Port: 8080,
Host: "localhost",
ReadTimeout: 10,
WriteTimeout: 10,
},
Database: DatabaseConfig{
DSN: "user:pass@tcp(localhost:3306)/dbname",
MaxIdleConns: 10,
MaxOpenConns: 100,
ConnMaxLifetime: 3600,
},
Log: LogConfig{
Level: "info",
Format: "json",
File: "app.log",
},
}
// 保存默认配置
if err := SaveConfig(defaultConfig, configPath); err != nil {
fmt.Println("Error saving config:", err)
return
}
// 加载配置
config, err := LoadConfig(configPath)
if err != nil {
fmt.Println("Error loading config:", err)
return
}
fmt.Println("Config loaded successfully:")
fmt.Printf("Server: %s:%d\n", config.Server.Host, config.Server.Port)
fmt.Printf("Database: %s\n", config.Database.DSN)
fmt.Printf("Log: %s level, %s format\n", config.Log.Level, config.Log.Format)
}7. 行业最佳实践
7.1 实践内容:优先使用标准库
推荐理由:标准库经过充分测试和优化,性能可靠,且与 Go 版本同步更新 示例代码:
go
// 推荐:使用标准库的 JSON 编解码
import "encoding/json"
// 不推荐:使用第三方 JSON 库(除非有特殊需求)
// import "github.com/json-iterator/go"7.2 实践内容:正确处理错误
推荐理由:标准库函数通常返回 error 类型,正确处理这些错误可以提高程序的可靠性 示例代码:
go
// 推荐:正确处理错误
resp, err := http.Get("https://example.com")
if err != nil {
return fmt.Errorf("error sending request: %w", err)
}
defer resp.Body.Close()
// 不推荐:忽略错误
// resp, _ := http.Get("https://example.com")7.3 实践内容:使用 context 管理生命周期
推荐理由:context 包提供了取消操作、超时控制等功能,适合管理请求和 goroutine 的生命周期 示例代码:
go
// 推荐:使用 context 控制超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "https://example.com", nil)
if err != nil {
return err
}
resp, err := http.DefaultClient.Do(req)7.4 实践内容:使用 defer 确保资源释放
推荐理由:defer 语句可以确保资源在函数返回时被正确释放,避免资源泄漏 示例代码:
go
// 推荐:使用 defer 关闭文件
file, err := os.Open("example.txt")
if err != nil {
return err
}
defer file.Close()
// 不推荐:手动关闭文件(容易遗漏)
// file, err := os.Open("example.txt")
// if err != nil {
// return err
// }
// // 处理文件
// file.Close()7.5 实践内容:了解标准库的性能特性
推荐理由:不同的标准库函数有不同的性能特性,了解这些特性可以写出更高效的代码 示例代码:
go
// 推荐:对于频繁的字符串拼接,使用 strings.Builder
var builder strings.Builder
for i := 0; i < 1000; i++ {
builder.WriteString("hello")
}
result := builder.String()
// 不推荐:使用 + 运算符拼接大量字符串
// var result string
// for i := 0; i < 1000; i++ {
// result += "hello"
// }8. 常见问题答疑(FAQ)
8.1 问题描述:如何选择标准库包?
回答内容:根据需要实现的功能选择相应的标准库包。例如,处理 HTTP 请求使用 net/http 包,处理 JSON 数据使用 encoding/json 包,处理文件操作使用 os 和 io 包等。 示例代码:
go
// 根据功能选择包
import (
"fmt" // 格式化输入输出
"net/http" // HTTP 客户端和服务器
"encoding/json" // JSON 编解码
"os" // 操作系统功能
"sync" // 并发原语
)8.2 问题描述:标准库包的版本如何管理?
回答内容:标准库包的版本与 Go 语言版本绑定,使用特定版本的 Go 会包含相应版本的标准库。在 go.mod 文件中不需要单独指定标准库的版本。 示例代码:
go
// go.mod 文件中只需要指定 Go 版本
module github.com/example/project
go 1.20
// 不需要指定标准库版本
// require (
// fmt v1.20.0 // 错误:标准库不需要指定版本
// )8.3 问题描述:如何查看标准库的文档?
回答内容:可以通过以下方式查看标准库文档:
- 访问官方文档:https://golang.org/pkg/
- 使用
go doc命令查看本地文档 - 在 IDE 中查看内置文档 示例代码:
bash
# 查看 fmt 包文档
go doc fmt
# 查看 http 包的 HandleFunc 函数文档
go doc net/http.HandleFunc8.4 问题描述:标准库包与第三方包的选择?
回答内容:优先使用标准库包,因为它们经过充分测试和优化,且与 Go 版本同步更新。只有当标准库无法满足需求时,才考虑使用第三方包。 示例代码:
go
// 优先使用标准库
import "encoding/json" // 标准库 JSON 包
// 当标准库无法满足需求时使用第三方包
// import "github.com/json-iterator/go" // 第三方 JSON 包8.5 问题描述:如何扩展标准库包?
回答内容:可以通过以下方式扩展标准库包:
- 创建包装函数,添加额外功能
- 实现标准库定义的接口
- 使用组合方式扩展功能 示例代码:
go
// 扩展 http.Handler
type MyHandler struct {
http.Handler
Logger *log.Logger
}
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.Logger.Println("Request received:", r.URL.Path)
h.Handler.ServeHTTP(w, r)
h.Logger.Println("Request completed:", r.URL.Path)
}8.6 问题描述:标准库包的性能如何?
回答内容:标准库包经过精心优化,性能通常非常好。但在使用时仍需注意一些性能细节,例如:
- 对于频繁的字符串操作,使用 strings.Builder
- 对于大文件操作,使用 bufio 包
- 对于并发操作,合理使用 sync 包的原语 示例代码:
go
// 性能优化示例
// 1. 使用 strings.Builder 进行字符串拼接
var builder strings.Builder
for i := 0; i < 1000; i++ {
builder.WriteString("hello")
}
// 2. 使用 bufio 读取大文件
file, _ := os.Open("largefile.txt")
reader := bufio.NewReader(file)
for {
line, err := reader.ReadString('\n')
if err != nil {
break
}
// 处理行
}9. 实战练习
9.1 基础练习:使用标准库创建 HTTP 服务器
解题思路:使用 net/http 包创建一个简单的 HTTP 服务器,实现基本的路由和响应 常见误区:未正确处理错误,未设置正确的 Content-Type 头 分步提示:
- 导入 net/http 包
- 注册路由处理函数
- 实现处理函数,设置响应头和状态码
- 启动服务器
- 测试服务器 参考代码:
go
package main
import (
"fmt"
"net/http"
)
func main() {
// 注册路由
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, World!"))
})
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"message": "Hello, API!"}`))
})
// 启动服务器
fmt.Println("Server running on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}9.2 进阶练习:实现 JSON API
解题思路:使用 encoding/json 包和 net/http 包实现一个 JSON API,支持 GET 和 POST 请求 常见误区:结构体字段未导出,JSON 编解码错误处理不当 分步提示:
- 定义数据模型结构体
- 实现 GET 请求处理函数,返回 JSON 数据
- 实现 POST 请求处理函数,解析 JSON 请求体
- 注册路由
- 启动服务器并测试 参考代码:
go
package main
import (
"encoding/json"
"fmt"
"net/http"
)
// 数据模型
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
// 模拟数据库
var users = []User{
{ID: 1, Name: "John Doe", Email: "john@example.com"},
{ID: 2, Name: "Jane Smith", Email: "jane@example.com"},
}
// GET /users
func getUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(users)
}
// POST /users
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "Invalid request body"})
return
}
// 生成 ID
user.ID = len(users) + 1
users = append(users, user)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
func main() {
// 注册路由
http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
getUsers(w, r)
case http.MethodPost:
createUser(w, r)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
})
// 启动服务器
fmt.Println("Server running on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}9.3 挑战练习:实现并发任务处理器
解题思路:使用 sync 和 context 包实现一个并发任务处理器,支持任务提交、取消和结果收集 常见误区:goroutine 泄漏,资源未正确释放,并发安全问题 分步提示:
- 定义任务类型和工作池结构
- 实现工作池的创建和工作协程
- 实现任务提交方法
- 实现工作池关闭和结果收集方法
- 测试并发任务处理 参考代码:
go
package main
import (
"context"
"fmt"
"sync"
"time"
)
// 任务函数
type Task func() (interface{}, error)
// 工作池
type WorkerPool struct {
ctx context.Context
cancel context.CancelFunc
taskChan chan Task
resultChan chan Result
workerWg sync.WaitGroup
}
// 任务结果
type Result struct {
Value interface{}
Error error
}
// 创建工作池
func NewWorkerPool(size int) *WorkerPool {
ctx, cancel := context.WithCancel(context.Background())
pool := &WorkerPool{
ctx: ctx,
cancel: cancel,
taskChan: make(chan Task, 100),
resultChan: make(chan Result, 100),
}
// 启动工作协程
for i := 0; i < size; i++ {
pool.workerWg.Add(1)
go pool.worker(i)
}
return pool
}
// 工作协程
func (p *WorkerPool) worker(id int) {
defer p.workerWg.Done()
for {
select {
case <-p.ctx.Done():
return
case task, ok := <-p.taskChan:
if !ok {
return
}
value, err := task()
p.resultChan <- Result{Value: value, Error: err}
}
}
}
// 添加任务
func (p *WorkerPool) AddTask(task Task) {
p.taskChan <- task
}
// 关闭工作池并收集结果
func (p *WorkerPool) Close() []Result {
close(p.taskChan)
p.workerWg.Wait()
close(p.resultChan)
// 收集结果
var results []Result
for result := range p.resultChan {
results = append(results, result)
}
p.cancel()
return results
}
func main() {
// 创建工作池
pool := NewWorkerPool(5)
// 添加任务
for i := 1; i <= 10; i++ {
taskID := i
pool.AddTask(func() (interface{}, error) {
time.Sleep(time.Duration(taskID) * 100 * time.Millisecond)
return fmt.Sprintf("Task %d result", taskID), nil
})
}
// 关闭工作池并收集结果
results := pool.Close()
// 打印结果
for i, result := range results {
if result.Error != nil {
fmt.Printf("Result %d: Error - %v\n", i+1, result.Error)
} else {
fmt.Printf("Result %d: %v\n", i+1, result.Value)
}
}
}10. 知识点总结
10.1 核心要点
- 标准库结构:核心层、工具层、平台层、扩展层
- 常用包:fmt、net/http、encoding/json、os、io、sync、context 等
- 设计理念:简洁性、一致性、高性能、可靠性、可扩展性
- 使用规范:优先使用标准库,正确处理错误,使用 context 管理生命周期,使用 defer 确保资源释放
- 性能优化:了解标准库的性能特性,选择合适的函数和数据结构
- 版本管理:标准库版本与 Go 版本绑定,不需要单独指定版本
10.2 易错点回顾
- HTTP 服务器未关闭:导致资源泄漏
- JSON 编解码失败:结构体字段未导出或类型不支持
- 文件操作未关闭:导致文件句柄泄漏
- 并发安全问题:未加锁保护共享资源
- 超时处理不当:导致程序阻塞
- 内存泄漏:未释放不再使用的资源
11. 拓展参考资料
11.1 官方文档链接
11.2 进阶学习路径建议
- 深入学习标准库的核心包:fmt、net/http、encoding/json 等
- 学习标准库的并发原语:sync、context 等
- 了解标准库的底层实现原理
- 学习如何扩展标准库功能
- 探索标准库在实际项目中的应用
本知识点承接《版本控制》,后续延伸至《第三方包》,建议学习顺序:版本控制 → 标准库包 → 第三方包 → 包的组织与结构
