znlgis 博客

GIS开发与技术分享 — GDAL · GeoServer · PostGIS · QGIS · OpenLayers · Cesium · FreeCAD · NPOI

第11章 - 标准库详解

Go 的标准库设计精良、功能强大,许多生产级程序仅依赖标准库即可完成。本章介绍最常用的标准库包,掌握它们能极大提升开发效率。完整文档可在 https://pkg.go.dev/std 查阅。

11.1 fmt:格式化 I/O

fmt 提供格式化输入输出功能:

fmt.Println("简单输出")
fmt.Printf("格式化: %d %s\n", 42, "hello")
s := fmt.Sprintf("拼接到字符串: %v", data) // 返回字符串而非打印
fmt.Fprintf(os.Stderr, "写到指定 Writer\n") // 输出到任意 io.Writer

// 输入
var name string
fmt.Scanln(&name)

11.2 strings:字符串处理

import "strings"

strings.Contains("hello", "ell")        // true
strings.HasPrefix("golang", "go")       // true
strings.HasSuffix("file.go", ".go")     // true
strings.Index("chicken", "ken")         // 4
strings.Replace("aaa", "a", "b", 2)     // "bba"(替换前 2 个)
strings.ReplaceAll("aaa", "a", "b")     // "bbb"
strings.Split("a,b,c", ",")             // ["a" "b" "c"]
strings.Join([]string{"a", "b"}, "-")   // "a-b"
strings.ToUpper("go")                    // "GO"
strings.ToLower("GO")                    // "go"
strings.TrimSpace("  hi  ")             // "hi"
strings.Trim("[hi]", "[]")              // "hi"
strings.Repeat("ab", 3)                  // "ababab"
strings.Fields("  a b   c ")            // ["a" "b" "c"],按空白分割

11.2.1 strings.Builder 高效拼接

频繁拼接字符串时,直接用 + 会产生大量临时对象。strings.Builder 通过缓冲避免重复分配,性能更优:

var b strings.Builder
for i := 0; i < 1000; i++ {
    b.WriteString("x")
}
result := b.String()

11.3 strconv:字符串与基本类型转换

import "strconv"

n, err := strconv.Atoi("123")          // string -> int
s := strconv.Itoa(123)                 // int -> string
f, err := strconv.ParseFloat("3.14", 64)
b, err := strconv.ParseBool("true")
i, err := strconv.ParseInt("ff", 16, 64) // 按 16 进制解析
str := strconv.FormatInt(255, 16)        // "ff"
quoted := strconv.Quote("hi\n")          // "\"hi\\n\""

11.4 strconv 与 errors

errors 包提供错误创建与处理(详见第 7 章):errors.Newerrors.Iserrors.Aserrors.Unwrapfmt.Errorf 配合 %w

11.5 time:时间与日期

import "time"

now := time.Now()
fmt.Println(now.Year(), now.Month(), now.Day())
fmt.Println(now.Unix())              // 时间戳(秒)

// 格式化:Go 使用特定的参考时间 2006-01-02 15:04:05
fmt.Println(now.Format("2006-01-02 15:04:05"))

// 解析
t, err := time.Parse("2006-01-02", "2024-03-15")

// 时间运算
later := now.Add(2 * time.Hour)
diff := later.Sub(now)               // Duration
fmt.Println(now.Before(later))       // true

// 定时器
time.Sleep(time.Second)
timer := time.NewTimer(3 * time.Second)
ticker := time.NewTicker(time.Second) // 周期性触发

记忆技巧:Go 的时间格式化模板使用固定参考时间 Mon Jan 2 15:04:05 MST 2006(对应数字 1 2 3 4 5 6 7),而非 YYYY-MM-DD

11.6 os:操作系统交互

import "os"

args := os.Args               // 命令行参数,args[0] 是程序名
val := os.Getenv("HOME")      // 读取环境变量
os.Setenv("KEY", "value")
os.Exit(1)                    // 退出程序

// 文件操作
f, err := os.Open("file.txt")        // 只读打开
f, err := os.Create("new.txt")       // 创建/截断
data, err := os.ReadFile("file.txt") // 一次性读取全部
err := os.WriteFile("out.txt", data, 0644)
os.Remove("file.txt")
os.Mkdir("dir", 0755)
os.MkdirAll("a/b/c", 0755)

11.7 io 与 bufio:I/O 抽象

io 包定义了 Reader/Writer 等核心接口。bufio 提供带缓冲的读写,减少系统调用:

import (
    "bufio"
    "os"
)

f, _ := os.Open("file.txt")
defer f.Close()

scanner := bufio.NewScanner(f)
for scanner.Scan() {     // 逐行读取
    line := scanner.Text()
    fmt.Println(line)
}

writer := bufio.NewWriter(os.Stdout)
writer.WriteString("buffered\n")
writer.Flush()           // 必须 Flush 才会真正写出

11.8 encoding/json:JSON 处理

JSON 是最常用的数据交换格式。Go 通过结构体标签控制序列化:

import "encoding/json"

type User struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email,omitempty"` // 为空时省略
    pwd   string // 未导出字段不会被序列化
}

// 序列化(Marshal)
user := User{Name: "Alice", Age: 30}
data, err := json.Marshal(user)        // {"name":"Alice","age":30}
data, err = json.MarshalIndent(user, "", "  ") // 带缩进

// 反序列化(Unmarshal)
var u User
err = json.Unmarshal(data, &u)

// 处理任意 JSON
var result map[string]any
json.Unmarshal(data, &result)

11.9 net/http:HTTP 客户端与服务端

详见第 15 章。这里给出最简示例:

// 客户端
resp, err := http.Get("https://api.example.com")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)

// 服务端
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello")
})
http.ListenAndServe(":8080", nil)

11.10 sort:排序

import "sort"

nums := []int{3, 1, 2}
sort.Ints(nums)                  // 升序
sort.Strings([]string{"c", "a"})
sort.Float64s(floats)

// 自定义排序
people := []Person{...}
sort.Slice(people, func(i, j int) bool {
    return people[i].Age < people[j].Age
})

// 二分查找(要求已排序)
idx := sort.SearchInts(nums, 2)

11.11 regexp:正则表达式

import "regexp"

re := regexp.MustCompile(`\d+`)
re.MatchString("abc123")        // true
re.FindString("abc123def")      // "123"
re.FindAllString("a1b2c3", -1)  // ["1" "2" "3"]
re.ReplaceAllString("a1b2", "X") // "aXbX"

11.12 slices 与 maps(Go 1.21+)

Go 1.21 将常用的泛型集合操作纳入标准库:

import (
    "slices"
    "maps"
)

s := []int{3, 1, 2}
slices.Sort(s)                       // [1 2 3]
slices.Contains(s, 2)                // true
slices.Index(s, 2)                   // 1
slices.Max(s)                        // 3
slices.Reverse(s)

m := map[string]int{"a": 1, "b": 2}
keys := slices.Collect(maps.Keys(m)) // 提取所有键
maps.Clone(m)                        // 浅拷贝

11.13 log 与 log/slog:日志

import "log"

log.Println("普通日志")
log.Printf("格式化: %d", 42)
log.Fatal("致命错误")  // 打印后调用 os.Exit(1)

// Go 1.21+ 的结构化日志 slog
import "log/slog"
slog.Info("用户登录", "userID", 123, "ip", "1.2.3.4")
slog.Error("操作失败", "err", err)

slog 提供结构化日志,输出可为文本或 JSON 格式,便于日志系统采集分析。

11.14 其他常用包速览

用途
bytes 字节切片操作,bytes.Buffer 高效拼接
bufio 带缓冲 I/O
path/filepath 跨平台文件路径处理
flag 命令行参数解析
math / math/rand 数学函数与随机数
encoding/base64 Base64 编码
crypto/md5crypto/sha256 哈希算法
net/url URL 解析
container/listcontainer/heap 链表、堆
unicode/utf8 UTF-8 处理

11.15 本章小结

本章介绍了 Go 标准库中最常用的包:fmtstringsstrconvtimeosio/bufioencoding/jsonnet/httpsortregexp,以及 Go 1.21 新增的 slices/maps 和结构化日志 slog。Go 标准库覆盖面广、质量高,熟练使用它们是高效开发的前提。建议养成查阅 pkg.go.dev 官方文档的习惯。

下一章我们将学习测试、基准测试与性能分析。