Go语言实战教程

教程简介

Go语言实战入门教程,涵盖并发编程、HTTP服务开发、数据库操作等核心实战内容,配有丰富代码示例和两个完整实战项目,适合后端开发学习者。

Go语言实战教程

从零开始掌握Go语言,从基础语法到并发编程,从Web开发到爬虫实战,全面覆盖Go语言核心知识体系。


目录

  1. Go语言简介与历史
  2. 环境搭建与配置
  3. 基本语法与数据类型
  4. 变量与常量
  5. 控制流语句
  6. 函数与方法
  7. 数组、切片与映射
  8. 结构体与接口
  9. 并发编程:goroutine与channel
  10. 包管理与模块
  11. 错误处理
  12. 文件I/O
  13. HTTP服务开发
  14. 数据库操作
  15. JSON处理
  16. 测试与基准测试
  17. 依赖管理
  18. 常用标准库
  19. 实战:RESTful API服务
  20. 实战:并发爬虫
  21. 部署与优化

1. Go语言简介与历史

1.1 Go语言的诞生背景

Go语言(又称Golang)是Google公司于2009年正式发布的一款开源编程语言。它的诞生源于Google内部对大规模软件工程中遇到的痛点:C++的编译速度过慢、Java的冗长繁琐、Python的性能不足。三位核心创始人——Robert Griesemer、Rob Pike和Ken Thompson——希望创造一门兼具高效编译、高性能运行和简洁语法的现代编程语言。

Ken Thompson是Unix操作系统的联合创始人,Rob Pike是UTF-8编码的共同发明人,Robert Griesemer参与了V8 JavaScript引擎和Java HotSpot编译器的开发。这样的创始团队赋予了Go语言深厚的系统编程基因。

1.2 Go语言的设计哲学

Go语言的设计遵循以下核心原则:

  • 简洁性(Simplicity):Go语言的语法非常精简,关键字仅有25个。没有类继承、没有异常机制(使用错误返回值)、没有泛型(Go 1.18开始支持有限泛型),这些设计选择都是为了降低语言的复杂度。
  • 并发原生(Concurrency):Go语言从语言层面原生支持并发编程,goroutine和channel是其核心并发原语,使得编写高并发程序变得简单直观。
  • 快速编译(Fast Compilation):Go语言的编译器经过精心设计,即使是大型项目也能在秒级完成编译,极大地提升了开发效率。
  • 静态类型与垃圾回收(Static Typing with GC):Go语言是静态类型语言,但拥有自动垃圾回收机制,开发者无需手动管理内存。
  • 跨平台编译(Cross-Platform):Go语言内置交叉编译支持,可以轻松编译出适用于不同操作系统和架构的可执行文件。

1.3 Go语言的版本演进

版本 发布时间 重要特性
Go 1.0 2012年3月 第一个稳定版本,确定了Go 1兼容性承诺
Go 1.5 2015年8月 编译器完全用Go重写,移除了C代码
Go 1.11 2018年8月 引入Go Modules依赖管理系统
Go 1.18 2022年3月 引入泛型(Generics)、模糊测试
Go 1.21 2023年8月 新增内置函数min/max/clear,slog结构化日志
Go 1.22 2024年2月 for循环变量语义改进,增强路由模式

1.4 Go语言的应用场景

Go语言在以下领域有着广泛的应用:

  • 云原生基础设施:Docker、Kubernetes、etcd、Prometheus等核心云原生项目均使用Go语言开发。
  • 微服务架构:Go语言的高性能和低内存占用使其成为微服务开发的理想选择。
  • 网络编程:Go标准库提供了强大的HTTP/TCP/UDP支持,非常适合开发网络服务。
  • 命令行工具:Go编译后生成单一可执行文件,无需运行时依赖,非常适合开发CLI工具。
  • 区块链:以太坊的Go实现(go-ethereum)是最主流的以太坊客户端之一。

2. 环境搭建与配置

2.1 安装Go语言

Linux/macOS安装

从官方下载页面获取最新版本的安装包:

# Linux - 下载并解压
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz

# 添加到PATH环境变量(写入 ~/.bashrc 或 ~/.zshrc)
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

# 使配置生效
source ~/.bashrc

Windows安装

https://go.dev/dl/ 下载Windows安装程序(.msi文件),双击运行安装向导即可。安装程序会自动配置环境变量。

验证安装

go version
# 输出: go version go1.22.0 linux/amd64

go env
# 查看所有Go环境变量

2.2 配置Go工作空间

Go语言从1.11版本开始推荐使用Go Modules管理项目,不再强制要求GOPATH模式。但了解GOPATH仍然重要:

# 查看关键环境变量
go env GOPATH      # 默认: ~/go
go env GOROOT      # Go安装目录
go env GOPROXY     # 模块代理地址

# 推荐配置国内镜像代理(中国大陆用户)
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GONOSUMCHECK=*

2.3 第一个Go程序

创建项目目录并初始化模块:

mkdir hello-go && cd hello-go
go mod init hello-go

创建 main.go 文件:

package main

import "fmt"

func main() {
    fmt.Println("你好,Go语言!")
    fmt.Printf("Go版本: %s\n", "1.22")
}

运行与编译:

# 直接运行
go run main.go

# 编译为可执行文件
go build -o hello main.go
./hello

2.4 开发工具推荐

  • GoLand:JetBrains出品的专业Go IDE,功能最全面,但需要付费。
  • VS Code + Go扩展:免费且功能强大,配合gopls语言服务器使用体验极佳。
  • Vim/Neovim + vim-go:适合终端用户,vim-go插件提供了完善的Go开发支持。

3. 基本语法与数据类型

3.1 程序结构

每个Go程序都由包(package)组成,main包是程序的入口:

// 声明包名
package main

// 导入标准库包
import (
    "fmt"
    "time"
)

// main函数是程序入口
func main() {
    // 单行注释
    /* 
       多行注释
    */
    fmt.Println("当前时间:", time.Now())
}

Go语言的几个重要语法规则:

  • 语句末尾不需要分号(编译器自动添加)
  • 左花括号 { 必须与语句在同一行,不能另起一行
  • 导入的包如果未使用,编译会报错
  • 未使用的变量也会导致编译错误

3.2 基本数据类型

Go语言提供了丰富的基本数据类型:

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    // ===== 整数类型 =====
    var a int = 42            // 平台相关(32位或64位)
    var b int8 = 127          // -128 到 127
    var c int16 = 32767       // -32768 到 32767
    var d int32 = 2147483647  // 约±21亿
    var e int64 = 9223372036854775807 // 约±9.2×10^18

    fmt.Printf("int: %d, 大小: %d字节\n", a, unsafe.Sizeof(a))
    fmt.Printf("int8: %d, 大小: %d字节\n", b, unsafe.Sizeof(b))
    fmt.Printf("int16: %d, 大小: %d字节\n", c, unsafe.Sizeof(c))
    fmt.Printf("int32: %d, 大小: %d字节\n", d, unsafe.Sizeof(d))
    fmt.Printf("int64: %d, 大小: %d字节\n", e, unsafe.Sizeof(e))

    // 无符号整数
    var ua uint = 42
    var ub uint8 = 255        // 0 到 255
    var uc uint16 = 65535     // 0 到 65535
    var ud uint32 = 4294967295
    var ue uint64 = 18446744073709551615
    _ = ua; _ = ub; _ = uc; _ = ud; _ = ue

    // 特殊整数类型
    var by byte = 255         // 等同于 uint8
    var r rune = '中'         // 等同于 int32,表示Unicode码点
    _ = by
    fmt.Printf("rune '中' 的值: %d, 字符: %c\n", r, r)

    // ===== 浮点数类型 =====
    var f32 float32 = 3.14159
    var f64 float64 = 3.141592653589793
    fmt.Printf("float32: %.5f\n", f32)
    fmt.Printf("float64: %.15f\n", f64)

    // ===== 复数类型 =====
    var c64 complex64 = complex(1, 2)       // 1+2i
    var c128 complex128 = complex(3.14, 2.7) // 3.14+2.7i
    fmt.Printf("complex64: %v\n", c64)
    fmt.Printf("complex128: %v\n", c128)

    // ===== 布尔类型 =====
    var flag bool = true
    var ok bool = false
    fmt.Printf("flag: %v, ok: %v\n", flag, ok)

    // ===== 字符串类型 =====
    var s string = "Hello, 世界!"
    fmt.Printf("字符串: %s, 长度: %d字节, 字符数: %d\n",
        s, len(s), len([]rune(s)))

    // 字符串是不可变的
    // s[0] = 'h' // 编译错误:不能修改字符串

    // 原始字符串(反引号)
    var raw string = `这是
一段多行
原始字符串`
    fmt.Println(raw)
}

3.3 类型转换

Go语言不支持隐式类型转换,所有类型转换必须显式进行:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 数值类型之间的转换
    var i int = 42
    var f float64 = float64(i)
    var u uint = uint(f)
    fmt.Printf("int: %d -> float64: %.2f -> uint: %d\n", i, f, u)

    // 整数与字符串之间的转换
    s := strconv.Itoa(42)          // int -> string
    n, err := strconv.Atoi("123")  // string -> int
    if err == nil {
        fmt.Printf("string: %s -> int: %d\n", s, n)
    }

    // 更多转换函数
    f2, _ := strconv.ParseFloat("3.14", 64)
    b, _ := strconv.ParseBool("true")
    fmt.Printf("float64: %.2f, bool: %v\n", f2, b)

    // 字符串与字节切片之间的转换(零拷贝优化)
    bs := []byte("Hello, Go!")
    str := string(bs)
    fmt.Printf("bytes: %v, string: %s\n", bs, str)
}

4. 变量与常量

4.1 变量声明

Go语言提供了多种变量声明方式:

package main

import "fmt"

// 包级别变量
var globalVar = "我是全局变量"
var (
    name    string = "Go"
    version int    = 22
    pi      float64 = 3.14159
)

func main() {
    // 方式一:var声明(指定类型)
    var age int = 30
    fmt.Println("age:", age)

    // 方式二:var声明(类型推断)
    var height = 175.5  // 自动推断为float64
    fmt.Println("height:", height)

    // 方式三:短变量声明(只能在函数内部使用)
    name := "张三"
    score := 95.5
    active := true
    fmt.Printf("name: %s, score: %.1f, active: %v\n", name, score, active)

    // 方式四:批量声明
    var (
        x int    = 1
        y string = "hello"
        z bool   = true
    )
    fmt.Println(x, y, z)

    // 多变量同时赋值
    a, b := 1, 2
    a, b = b, a // 交换值
    fmt.Printf("a: %d, b: %d\n", a, b)

    // 零值:未初始化的变量会被赋予默认零值
    var (
        zeroInt    int
        zeroFloat  float64
        zeroBool   bool
        zeroString string
        zeroPtr    *int
        zeroSlice  []int
        zeroMap    map[string]int
    )
    fmt.Printf("int零值: %d\n", zeroInt)         // 0
    fmt.Printf("float零值: %f\n", zeroFloat)     // 0.000000
    fmt.Printf("bool零值: %v\n", zeroBool)       // false
    fmt.Printf("string零值: %q\n", zeroString)   // ""
    fmt.Printf("指针零值: %v\n", zeroPtr)         // <nil>
    fmt.Printf("切片零值: %v, len: %d, nil: %v\n",
        zeroSlice, len(zeroSlice), zeroSlice == nil) // [] 0 true
    fmt.Printf("映射零值: %v, nil: %v\n",
        zeroMap, zeroMap == nil)                   // map[] true

    // 空白标识符 _
    _, second := 10, 20 // 忽略第一个值
    fmt.Println("second:", second)
}

4.2 常量

package main

import "fmt"

// 单个常量
const Pi = 3.14159265358979
const MaxRetries = 3

// 批量常量
const (
    StatusOK       = 200
    StatusNotFound = 404
    StatusError    = 500
)

// iota枚举器
type Weekday int

const (
    Sunday    Weekday = iota // 0
    Monday                   // 1
    Tuesday                  // 2
    Wednesday                // 3
    Thursday                 // 4
    Friday                   // 5
    Saturday                 // 6
)

// iota的高级用法
const (
    _  = iota             // 忽略0
    KB = 1 << (10 * iota) // 1 << 10 = 1024
    MB                    // 1 << 20 = 1048576
    GB                    // 1 << 30
    TB                    // 1 << 40
)

// iota参与运算
type Permission uint8

const (
    Read    Permission = 1 << iota // 1 (001)
    Write                          // 2 (010)
    Execute                        // 4 (100)
)

// 无类型常量
const (
    UntypedInt    = 42           // 无类型整数常量
    UntypedFloat  = 3.14         // 无类型浮点常量
    UntypedString = "hello"      // 无类型字符串常量
    UntypedBool   = true         // 无类型布尔常量
)

func main() {
    fmt.Printf("Pi: %f\n", Pi)
    fmt.Printf("Sunday: %d, Saturday: %d\n", Sunday, Saturday)
    fmt.Printf("KB: %d, MB: %d, GB: %d, TB: %d\n", KB, MB, GB, TB)

    // 权限组合(位运算)
    var perm Permission = Read | Write  // 011 = 3
    fmt.Printf("权限: %d, 可读: %v, 可写: %v, 可执行: %v\n",
        perm, perm&Read != 0, perm&Write != 0, perm&Execute != 0)

    // 无类型常量可以隐式转换为兼容类型
    var x int = UntypedInt         // int
    var y float64 = UntypedFloat   // float64
    var z complex128 = UntypedInt  // complex128
    fmt.Printf("x: %d, y: %f, z: %v\n", x, y, z)
}

5. 控制流语句

5.1 条件语句

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    // 基本if语句
    score := 85
    if score >= 90 {
        fmt.Println("优秀")
    } else if score >= 80 {
        fmt.Println("良好")
    } else if score >= 60 {
        fmt.Println("及格")
    } else {
        fmt.Println("不及格")
    }

    // if带初始化语句
    if num := rand.Intn(100); num > 50 {
        fmt.Printf("随机数 %d 大于50\n", num)
    } else {
        fmt.Printf("随机数 %d 小于等于50\n", num)
    }

    // switch语句
    day := "Wednesday"
    switch day {
    case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
        fmt.Println("工作日")
    case "Saturday", "Sunday":
        fmt.Println("周末")
    default:
        fmt.Println("未知")
    }

    // 无条件switch(替代长if-else链)
    temperature := 35
    switch {
    case temperature > 35:
        fmt.Println("酷热")
    case temperature > 25:
        fmt.Println("温暖")
    case temperature > 10:
        fmt.Println("凉爽")
    default:
        fmt.Println("寒冷")
    }

    // 类型switch
    var i interface{} = "hello"
    switch v := i.(type) {
    case int:
        fmt.Printf("整数: %d\n", v)
    case string:
        fmt.Printf("字符串: %s\n", v)
    case bool:
        fmt.Printf("布尔: %v\n", v)
    default:
        fmt.Printf("未知类型: %T\n", v)
    }
}

5.2 循环语句

Go语言只有for一种循环语句,但它可以模拟所有循环模式:

package main

import "fmt"

func main() {
    // 标准for循环
    sum := 0
    for i := 1; i <= 100; i++ {
        sum += i
    }
    fmt.Println("1到100的和:", sum)

    // while风格
    n := 1
    for n < 1000 {
        n *= 2
    }
    fmt.Println("最小的>=1000的2的幂:", n)

    // 无限循环
    count := 0
    for {
        count++
        if count > 5 {
            break
        }
        if count%2 == 0 {
            continue // 跳过偶数
        }
        fmt.Println("奇数:", count)
    }

    // range遍历
    // 遍历字符串(按rune)
    for i, ch := range "Hello, 世界" {
        fmt.Printf("索引: %d, 字符: %c, 码点: %d\n", i, ch, ch)
    }

    // 遍历切片
    fruits := []string{"苹果", "香蕉", "橙子", "葡萄"}
    for index, value := range fruits {
        fmt.Printf("索引: %d, 值: %s\n", index, value)
    }

    // 只需要索引
    for i := range fruits {
        fmt.Println("索引:", i)
    }

    // 只需要值
    for _, fruit := range fruits {
        fmt.Println("水果:", fruit)
    }

    // 遍历映射
    scores := map[string]int{
        "数学": 95,
        "英语": 88,
        "物理": 92,
    }
    for subject, score := range scores {
        fmt.Printf("%s: %d分\n", subject, score)
    }

    // goto语句(谨慎使用)
    x := 0
Retry:
    x++
    if x < 3 {
        fmt.Printf("重试第%d次\n", x)
        goto Retry
    }
    fmt.Println("完成")
}

6. 函数与方法

6.1 函数基础

package main

import (
    "errors"
    "fmt"
)

// 基本函数
func add(a, b int) int {
    return a + b
}

// 多参数类型相同可以简写
func multiply(a, b int) int {
    return a * b
}

// 多返回值
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

// 命名返回值
func rectangle(length, width float64) (area, perimeter float64) {
    area = length * width
    perimeter = 2 * (length + width)
    return // 裸返回,自动返回命名的返回值
}

// 可变参数函数
func sum(numbers ...int) int {
    total := 0
    for _, n := range numbers {
        total += n
    }
    return total
}

// 函数作为参数(高阶函数)
func apply(fn func(int, int) int, a, b int) int {
    return fn(a, b)
}

// 函数作为返回值
func makeMultiplier(factor int) func(int) int {
    return func(x int) int {
        return x * factor
    }
}

// 闭包
func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

// 递归
func fibonacci(n int) int {
    if n <= 1 {
        return n
    }
    return fibonacci(n-1) + fibonacci(n-2)
}

// defer语句
func readFile(filename string) {
    fmt.Printf("打开文件: %s\n", filename)
    defer fmt.Printf("关闭文件: %s\n", filename) // 最后执行
    defer fmt.Println("清理资源...") // 后进先出(LIFO)
    fmt.Printf("读取文件: %s\n", filename)
}

// panic与recover
func safeDivide(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("捕获到异常: %v", r)
        }
    }()

    if b == 0 {
        panic("除以零")
    }
    return a / b, nil
}

func main() {
    fmt.Println("加法:", add(3, 5))
    fmt.Println("乘法:", multiply(4, 6))

    // 多返回值处理
    if result, err := divide(10, 3); err != nil {
        fmt.Println("错误:", err)
    } else {
        fmt.Printf("10 / 3 = %.4f\n", result)
    }

    // 命名返回值
    area, perimeter := rectangle(5, 3)
    fmt.Printf("面积: %.2f, 周长: %.2f\n", area, perimeter)

    // 可变参数
    fmt.Println("求和:", sum(1, 2, 3, 4, 5))

    // 切片展开
    nums := []int{10, 20, 30}
    fmt.Println("切片求和:", sum(nums...))

    // 高阶函数
    fmt.Println("apply add:", apply(add, 3, 5))

    // 闭包
    double := makeMultiplier(2)
    triple := makeMultiplier(3)
    fmt.Println("double 5:", double(5))
    fmt.Println("triple 5:", triple(5))

    // 计数器闭包
    next := counter()
    fmt.Println(next()) // 1
    fmt.Println(next()) // 2
    fmt.Println(next()) // 3

    // 递归
    fmt.Println("fibonacci(10):", fibonacci(10))

    // defer
    readFile("test.txt")

    // panic/recover
    r, err := safeDivide(10, 0)
    if err != nil {
        fmt.Println("错误:", err)
    } else {
        fmt.Println("结果:", r)
    }
}

6.2 方法

package main

import (
    "fmt"
    "math"
)

// 定义结构体
type Point struct {
    X, Y float64
}

// 值接收者方法
func (p Point) Distance(q Point) float64 {
    return math.Sqrt(math.Pow(p.X-q.X, 2) + math.Pow(p.Y-q.Y, 2))
}

// 指针接收者方法(可以修改结构体字段)
func (p *Point) Translate(dx, dy float64) {
    p.X += dx
    p.Y += dy
}

// 指针接收者方法
func (p *Point) Scale(factor float64) {
    p.X *= factor
    p.Y *= factor
}

func (p Point) String() string {
    return fmt.Sprintf("(%.2f, %.2f)", p.X, p.Y)
}

// 自定义类型的方法
type Celsius float64
type Fahrenheit float64

func (c Celsius) ToFahrenheit() Fahrenheit {
    return Fahrenheit(c*9/5 + 32)
}

func (f Fahrenheit) ToCelsius() Celsius {
    return Celsius((f - 32) * 5 / 9)
}

func main() {
    p1 := Point{3, 4}
    p2 := Point{0, 0}

    fmt.Printf("p1到p2的距离: %.2f\n", p1.Distance(p2))

    p1.Translate(1, 1)
    fmt.Println("平移后的p1:", p1)

    p1.Scale(2)
    fmt.Println("缩放后的p1:", p1)

    // 温度转换
    c := Celsius(100)
    f := c.ToFahrenheit()
    fmt.Printf("%.1f°C = %.1f°F\n", c, f)

    f2 := Fahrenheit(212)
    c2 := f2.ToCelsius()
    fmt.Printf("%.1f°F = %.1f°C\n", f2, c2)
}

7. 数组、切片与映射

7.1 数组

package main

import "fmt"

func main() {
    // 数组声明
    var arr1 [5]int                         // 零值数组
    arr2 := [5]int{1, 2, 3, 4, 5}         // 字面量初始化
    arr3 := [...]int{10, 20, 30}           // 编译器自动计算长度
    arr4 := [3]string{"Go", "Rust", "Python"}

    fmt.Println("arr1:", arr1)
    fmt.Println("arr2:", arr2)
    fmt.Println("arr3:", arr3)
    fmt.Println("arr4:", arr4)

    // 数组访问与修改
    arr2[0] = 100
    fmt.Println("修改后:", arr2)
    fmt.Println("长度:", len(arr2))

    // 数组是值类型
    a := [3]int{1, 2, 3}
    b := a          // 复制整个数组
    b[0] = 100
    fmt.Println("a:", a) // [1 2 3] 不受影响
    fmt.Println("b:", b) // [100 2 3]

    // 二维数组
    matrix := [3][3]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }
    for _, row := range matrix {
        fmt.Println(row)
    }
}

7.2 切片

切片是Go语言中最重要的数据结构之一,它是一个动态大小的序列:

package main

import "fmt"

func main() {
    // 创建切片
    s1 := []int{1, 2, 3, 4, 5}  // 字面量
    s2 := make([]int, 5)         // 长度5,容量5
    s3 := make([]int, 3, 10)     // 长度3,容量10
    var s4 []int                  // nil切片

    fmt.Println("s1:", s1, "len:", len(s1), "cap:", cap(s1))
    fmt.Println("s2:", s2, "len:", len(s2), "cap:", cap(s2))
    fmt.Println("s3:", s3, "len:", len(s3), "cap:", cap(s3))
    fmt.Println("s4:", s4, "nil:", s4 == nil)

    // 切片操作
    fmt.Println("s1[1:3]:", s1[1:3])  // [2 3]
    fmt.Println("s1[:3]:", s1[:3])    // [1 2 3]
    fmt.Println("s1[2:]:", s1[2:])    // [3 4 5]
    fmt.Println("s1[:]:", s1[:])      // [1 2 3 4 5]

    // append追加元素
    s1 = append(s1, 6)
    fmt.Println("追加后:", s1)

    // append追加多个元素
    s1 = append(s1, 7, 8, 9)
    fmt.Println("再追加:", s1)

    // append合并切片
    s5 := []int{10, 20, 30}
    s1 = append(s1, s5...)
    fmt.Println("合并后:", s1)

    // copy复制切片
    src := []int{1, 2, 3, 4, 5}
    dst := make([]int, 3)
    n := copy(dst, src)  // 复制前3个元素
    fmt.Printf("复制了%d个元素: %v\n", n, dst)

    // 删除切片元素(保持顺序)
    s := []int{1, 2, 3, 4, 5}
    index := 2
    s = append(s[:index], s[index+1:]...)  // 删除索引2的元素
    fmt.Println("删除后:", s)  // [1 2 4 5]

    // 删除切片元素(不保持顺序,更快)
    s2 = []int{1, 2, 3, 4, 5}
    s2[index] = s2[len(s2)-1]
    s2 = s2[:len(s2)-1]
    fmt.Println("快速删除:", s2)  // [1 2 5 4]

    // 切片的内部结构:指针、长度、容量
    original := []int{1, 2, 3, 4, 5}
    sub := original[1:3]
    fmt.Printf("sub: %v, len: %d, cap: %d\n", sub, len(sub), cap(sub))
    // sub共享底层数组
    sub[0] = 200
    fmt.Println("修改sub后original:", original)  // [1 200 3 4 5]

    // 使用copy创建独立副本
    independent := make([]int, len(original))
    copy(independent, original)
    independent[0] = 999
    fmt.Println("independent:", independent)
    fmt.Println("original不受影响:", original)

    // 预分配容量避免频繁扩容
    result := make([]int, 0, 1000)
    for i := 0; i < 1000; i++ {
        result = append(result, i*i)
    }
    fmt.Println("前10个:", result[:10])
}

7.3 映射(Map)

package main

import (
    "fmt"
    "sort"
)

func main() {
    // 创建映射
    m1 := map[string]int{
        "数学": 95,
        "英语": 88,
        "物理": 92,
    }
    m2 := make(map[string]int)  // 空映射
    var m3 map[string]int       // nil映射

    fmt.Println("m1:", m1)
    fmt.Println("m2:", m2)
    fmt.Println("m3:", m3, "nil:", m3 == nil)

    // 基本操作
    m2["Go"] = 100      // 添加/修改
    m2["Rust"] = 98
    m2["Python"] = 90
    fmt.Println("m2:", m2)

    // 读取
    score := m2["Go"]
    fmt.Println("Go成绩:", score)

    // 检查键是否存在
    if score, ok := m2["Java"]; ok {
        fmt.Println("Java成绩:", score)
    } else {
        fmt.Println("Java不在映射中")
    }

    // 删除
    delete(m2, "Python")
    fmt.Println("删除Python后:", m2)

    // 遍历映射(顺序不确定)
    for subject, score := range m1 {
        fmt.Printf("%s: %d\n", subject, score)
    }

    // 有序遍历映射
    keys := make([]string, 0, len(m1))
    for k := range m1 {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    fmt.Println("\n有序遍历:")
    for _, k := range keys {
        fmt.Printf("%s: %d\n", k, m1[k])
    }

    // 映射作为集合
    set := make(map[string]bool)
    fruits := []string{"苹果", "香蕉", "苹果", "橙子", "香蕉", "葡萄"}
    for _, f := range fruits {
        set[f] = true
    }
    fmt.Println("去重后的水果:")
    for f := range set {
        fmt.Println(" ", f)
    }

    // 映射的值是切片
    classScores := make(map[string][]int)
    classScores["一班"] = append(classScores["一班"], 90, 85, 92)
    classScores["二班"] = append(classScores["二班"], 88, 76, 95)
    fmt.Println("班级成绩:", classScores)

    // 嵌套映射
    students := map[string]map[string]int{
        "张三": {"数学": 95, "英语": 88},
        "李四": {"数学": 82, "英语": 90},
    }
    for name, scores := range students {
        fmt.Printf("%s的成绩: %v\n", name, scores)
    }
}

8. 结构体与接口

8.1 结构体

package main

import (
    "fmt"
    "time"
)

// 定义结构体
type User struct {
    ID        int
    Name      string
    Email     string
    Age       int
    CreatedAt time.Time
}

// 结构体方法
func (u User) String() string {
    return fmt.Sprintf("User{id=%d, name=%s, email=%s, age=%d}",
        u.ID, u.Name, u.Email, u.Age)
}

// 指针接收者方法
func (u *User) UpdateEmail(email string) {
    u.Email = email
}

// 构造函数(Go语言惯例:NewXxx)
func NewUser(id int, name, email string, age int) *User {
    return &User{
        ID:        id,
        Name:      name,
        Email:     email,
        Age:       age,
        CreatedAt: time.Now(),
    }
}

// 嵌入结构体(组合)
type Address struct {
    City    string
    Country string
}

type Employee struct {
    User              // 嵌入User,继承其字段和方法
    Company  string
    Position string
    Address  Address  // 命名嵌入
}

func (e Employee) FullInfo() string {
    return fmt.Sprintf("%s - %s @ %s (%s, %s)",
        e.Name, e.Position, e.Company, e.Address.City, e.Address.Country)
}

func main() {
    // 创建结构体实例
    u1 := User{
        ID:    1,
        Name:  "张三",
        Email: "zhangsan@example.com",
        Age:   25,
    }

    u2 := NewUser(2, "李四", "lisi@example.com", 30)
    fmt.Println(u1)
    fmt.Println(u2)

    // 访问和修改字段
    u1.Age = 26
    u1.UpdateEmail("zhangsan_new@example.com")
    fmt.Println("更新后:", u1)

    // 结构体切片
    users := []User{u1, *u2}
    for _, u := range users {
        fmt.Println(u)
    }

    // 匿名结构体
    point := struct {
        X, Y int
    }{10, 20}
    fmt.Println("匿名结构体:", point)

    // 嵌入结构体
    emp := Employee{
        User: User{
            ID:    3,
            Name:  "王五",
            Email: "wangwu@example.com",
            Age:   28,
        },
        Company:  "Google",
        Position: "软件工程师",
        Address: Address{
            City:    "北京",
            Country: "中国",
        },
    }

    // 直接访问嵌入结构体的字段
    fmt.Println("姓名:", emp.Name)   // 等同于 emp.User.Name
    fmt.Println("公司:", emp.Company)
    fmt.Println(emp.FullInfo())
}

8.2 接口

package main

import (
    "fmt"
    "math"
)

// 定义接口
type Shape interface {
    Area() float64
    Perimeter() float64
}

// 圆形
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}

func (c Circle) String() string {
    return fmt.Sprintf("圆形(半径=%.2f)", c.Radius)
}

// 矩形
type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func (r Rectangle) String() string {
    return fmt.Sprintf("矩形(宽=%.2f, 高=%.2f)", r.Width, r.Height)
}

// 三角形
type Triangle struct {
    A, B, C float64 // 三条边
}

func (t Triangle) Area() float64 {
    s := (t.A + t.B + t.C) / 2 // 半周长
    return math.Sqrt(s * (s - t.A) * (s - t.B) * (s - t.C))
}

func (t Triangle) Perimeter() float64 {
    return t.A + t.B + t.C
}

// 多态函数
func PrintShapeInfo(s Shape) {
    fmt.Printf("形状: %v\n", s)
    fmt.Printf("  面积: %.4f\n", s.Area())
    fmt.Printf("  周长: %.4f\n", s.Perimeter())
}

// 空接口
func describe(i interface{}) {
    fmt.Printf("类型: %T, 值: %v\n", i, i)
}

// 接口组合
type ReadWriter interface {
    Reader
    Writer
}

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

func main() {
    shapes := []Shape{
        Circle{Radius: 5},
        Rectangle{Width: 4, Height: 6},
        Triangle{A: 3, B: 4, C: 5},
    }

    for _, s := range shapes {
        PrintShapeInfo(s)
        fmt.Println()
    }

    // 类型断言
    var s Shape = Circle{Radius: 3}
    if c, ok := s.(Circle); ok {
        fmt.Printf("是圆形,半径: %.2f\n", c.Radius)
    }

    // 类型switch
    for _, shape := range shapes {
        switch v := shape.(type) {
        case Circle:
            fmt.Printf("圆形: 半径=%.2f\n", v.Radius)
        case Rectangle:
            fmt.Printf("矩形: 宽=%.2f, 高=%.2f\n", v.Width, v.Height)
        case Triangle:
            fmt.Printf("三角形: 三边=%.2f, %.2f, %.2f\n", v.A, v.B, v.C)
        }
    }

    // 空接口
    describe(42)
    describe("hello")
    describe(true)
    describe([]int{1, 2, 3})

    // 接口的零值
    var nilShape Shape
    fmt.Println("nil接口:", nilShape == nil) // true

    // 注意:持有nil指针的接口不等于nil
    var nilCircle *Circle
    var iface Shape = nilCircle
    fmt.Println("持有nil指针的接口:", iface == nil) // false!
}

9. 并发编程:goroutine与channel

Go语言的并发模型基于CSP(Communicating Sequential Processes)理论,核心概念是goroutine和channel。

9.1 Goroutine

package main

import (
    "fmt"
    "sync"
    "time"
)

func sayHello(name string) {
    for i := 0; i < 3; i++ {
        fmt.Printf("[%s] 你好!(%d)\n", name, i+1)
        time.Sleep(100 * time.Millisecond)
    }
}

func main() {
    // 启动goroutine
    go sayHello("goroutine-1")
    go sayHello("goroutine-2")

    // 使用匿名函数启动goroutine
    go func() {
        fmt.Println("匿名goroutine执行")
    }()

    // 等待goroutine完成(使用WaitGroup)
    var wg sync.WaitGroup

    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Worker %d 开始工作\n", id)
            time.Sleep(time.Duration(id*100) * time.Millisecond)
            fmt.Printf("Worker %d 完成工作\n", id)
        }(i)
    }

    wg.Wait()
    fmt.Println("所有worker已完成")
}

9.2 Channel

package main

import (
    "fmt"
    "time"
)

func main() {
    // 无缓冲channel(同步通信)
    ch := make(chan string)

    go func() {
        ch <- "Hello from goroutine!"
    }()

    msg := <-ch
    fmt.Println(msg)

    // 有缓冲channel(异步通信)
    bufferedCh := make(chan int, 3)

    bufferedCh <- 1
    bufferedCh <- 2
    bufferedCh <- 3
    // bufferedCh <- 4  // 会阻塞,因为缓冲区已满

    fmt.Println(<-bufferedCh) // 1
    fmt.Println(<-bufferedCh) // 2
    fmt.Println(<-bufferedCh) // 3

    // channel方向(只读/只写)
    // 只写channel: chan<- int
    // 只读channel: <-chan int

    // 使用channel实现生产者-消费者模式
    producer := func(ch chan<- int) {
        for i := 0; i < 10; i++ {
            ch <- i
            fmt.Printf("生产: %d\n", i)
        }
        close(ch) // 关闭channel
    }

    consumer := func(ch <-chan int) {
        for v := range ch { // 自动检测channel关闭
            fmt.Printf("消费: %d\n", v)
        }
    }

    ch2 := make(chan int, 3)
    go producer(ch2)
    consumer(ch2)
}

9.3 Select语句

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        time.Sleep(2 * time.Second)
        ch1 <- "来自channel 1"
    }()

    go func() {
        time.Sleep(1 * time.Second)
        ch2 <- "来自channel 2"
    }()

    // select等待多个channel
    for i := 0; i < 2; i++ {
        select {
        case msg := <-ch1:
            fmt.Println("收到:", msg)
        case msg := <-ch2:
            fmt.Println("收到:", msg)
        }
    }

    // select超时控制
    ch := make(chan string)
    go func() {
        time.Sleep(3 * time.Second)
        ch <- "结果"
    }()

    select {
    case result := <-ch:
        fmt.Println("获取结果:", result)
    case <-time.After(1 * time.Second):
        fmt.Println("超时!")
    }

    // select非阻塞操作
    ch3 := make(chan int, 1)
    select {
    case v := <-ch3:
        fmt.Println("收到:", v)
    default:
        fmt.Println("没有数据可读")
    }

    // 使用done channel实现优雅退出
    done := make(chan struct{})
    go func() {
        for {
            select {
            case <-done:
                fmt.Println("收到退出信号")
                return
            default:
                fmt.Println("工作中...")
                time.Sleep(500 * time.Millisecond)
            }
        }
    }()

    time.Sleep(2 * time.Second)
    close(done) // 发送退出信号
    time.Sleep(100 * time.Millisecond)
    fmt.Println("程序退出")
}

9.4 并发模式

package main

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

// Fan-out/Fan-in模式
func fanOutFanIn() {
    input := make(chan int)
    // 多个worker并发处理
    numWorkers := 3
    var wg sync.WaitGroup

    // Fan-out: 一个输入分发给多个worker
    for i := 0; i < numWorkers; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            for v := range input {
                fmt.Printf("Worker %d 处理: %d -> %d\n", id, v, v*v)
                time.Sleep(100 * time.Millisecond)
            }
        }(i)
    }

    // 发送数据
    for i := 1; i <= 10; i++ {
        input <- i
    }
    close(input)
    wg.Wait()
}

// Context控制goroutine生命周期
func contextDemo() {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    go func(ctx context.Context) {
        for {
            select {
            case <-ctx.Done():
                fmt.Println("Context取消:", ctx.Err())
                return
            default:
                fmt.Println("处理中...")
                time.Sleep(500 * time.Millisecond)
            }
        }
    }(ctx)

    time.Sleep(3 * time.Second)
    fmt.Println("主函数结束")
}

func main() {
    fmt.Println("=== Fan-out/Fan-in ===")
    fanOutFanIn()

    fmt.Println("\n=== Context控制 ===")
    contextDemo()
}

9.5 sync包常用工具

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

// Mutex互斥锁
type SafeCounter struct {
    mu    sync.Mutex
    count int
}

func (c *SafeCounter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

func (c *SafeCounter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}

// RWMutex读写锁
type SafeMap struct {
    mu   sync.RWMutex
    data map[string]string
}

func (m *SafeMap) Get(key string) (string, bool) {
    m.mu.RLock()         // 读锁:允许并发读
    defer m.mu.RUnlock()
    v, ok := m.data[key]
    return v, ok
}

func (m *SafeMap) Set(key, value string) {
    m.mu.Lock()          // 写锁:独占
    defer m.mu.Unlock()
    m.data[key] = value
}

func main() {
    // 互斥锁示例
    counter := &SafeCounter{}
    var wg sync.WaitGroup

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Increment()
        }()
    }
    wg.Wait()
    fmt.Println("最终计数:", counter.Value()) // 1000

    // 读写锁示例
    sm := &SafeMap{data: make(map[string]string)}
    sm.Set("name", "Go")
    sm.Set("version", "1.22")

    if v, ok := sm.Get("name"); ok {
        fmt.Println("name:", v)
    }

    // 原子操作(无锁,更高性能)
    var atomicCounter int64
    var wg2 sync.WaitGroup

    for i := 0; i < 1000; i++ {
        wg2.Add(1)
        go func() {
            defer wg2.Done()
            atomic.AddInt64(&atomicCounter, 1)
        }()
    }
    wg2.Wait()
    fmt.Println("原子计数:", atomic.LoadInt64(&atomicCounter))

    // Once只执行一次
    var once sync.Once
    init := func() {
        fmt.Println("初始化操作(只执行一次)")
    }

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            once.Do(init)
        }()
    }
    wg.Wait()

    // Pool对象池
    pool := &sync.Pool{
        New: func() interface{} {
            fmt.Println("创建新对象")
            return make([]byte, 1024)
        },
    }

    // 获取对象(可能新建)
    buf := pool.Get().([]byte)
    fmt.Printf("获取缓冲区: len=%d, cap=%d\n", len(buf), cap(buf))

    // 归还对象
    pool.Put(buf)

    // 再次获取(可能复用之前的)
    buf2 := pool.Get().([]byte)
    fmt.Printf("再次获取: %v\n", &buf == &buf2) // 可能是同一个
}

10. 包管理与模块

10.1 创建和使用包

项目结构:

myproject/
├── go.mod
├── main.go
├── mathutil/
│   ├── basic.go
│   └── advanced.go
└── stringutil/
    └── convert.go
// mathutil/basic.go
package mathutil

// Add 加法(导出函数,首字母大写)
func Add(a, b int) int {
    return a + b
}

// subtract 减法(未导出函数,首字母小写)
func subtract(a, b int) int {
    return a - b
}

// SubtractSubtractionResult 使用未导出函数
func SubtractResult(a, b int) int {
    return subtract(a, b)
}
// mathutil/advanced.go
package mathutil

import "math"

// Max 返回两个数中的较大值
func Max(a, b float64) float64 {
    return math.Max(a, b)
}

// Min 返回两个数中的较小值
func Min(a, b float64) float64 {
    return math.Min(a, b)
}
// stringutil/convert.go
package stringutil

import "strings"

// Reverse 反转字符串
func Reverse(s string) string {
    runes := []rune(s)
    for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
        runes[i], runes[j] = runes[j], runes[i]
    }
    return string(runes)
}

// ToTitleCase 首字母大写
func ToTitleCase(s string) string {
    return strings.Title(s)
}
// main.go
package main

import (
    "fmt"

    "myproject/mathutil"
    "myproject/stringutil"
)

func main() {
    fmt.Println("加法:", mathutil.Add(3, 5))
    fmt.Println("减法:", mathutil.SubtractResult(10, 4))
    fmt.Println("最大值:", mathutil.Max(3.14, 2.72))
    fmt.Println("反转:", stringutil.Reverse("Hello, Go!"))
}

10.2 Go Modules

# 初始化模块
go mod init github.com/username/myproject

# 添加依赖
go get github.com/gin-gonic/gin@latest
go get github.com/go-sql-driver/mysql@v1.7.0

# 整理依赖(添加缺少的,删除未使用的)
go mod tidy

# 下载依赖到本地缓存
go mod download

# 查看依赖图
go mod graph

# 验证依赖
go mod verify

# 将依赖复制到vendor目录
go mod vendor

go.mod文件示例:

module github.com/username/myproject

go 1.22

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/go-sql-driver/mysql v1.7.0
)

require (
    github.com/bytedance/sonic v1.9.1 // indirect
    github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abb8f00 // indirect
    // ... 更多间接依赖
)

11. 错误处理

11.1 基本错误处理

package main

import (
    "errors"
    "fmt"
    "os"
    "strconv"
)

// 自定义错误
var (
    ErrNotFound     = errors.New("资源未找到")
    ErrUnauthorized = errors.New("未授权访问")
    ErrInvalidInput = errors.New("无效输入")
)

// 返回错误的函数
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

// 带上下文信息的错误
func parseConfig(filename string) (map[string]string, error) {
    data, err := os.ReadFile(filename)
    if err != nil {
        return nil, fmt.Errorf("读取配置文件失败: %w", err)
    }
    // 解析配置...
    _ = data
    return map[string]string{"key": "value"}, nil
}

// 错误链(Go 1.13+)
func fetchUser(id int) (string, error) {
    if id <= 0 {
        return "", fmt.Errorf("用户ID无效: %w", ErrInvalidInput)
    }
    if id > 1000 {
        return "", fmt.Errorf("用户不存在: %w", ErrNotFound)
    }
    return "用户" + strconv.Itoa(id), nil
}

func main() {
    // 基本错误处理
    result, err := divide(10, 3)
    if err != nil {
        fmt.Println("错误:", err)
    } else {
        fmt.Printf("10 / 3 = %.4f\n", result)
    }

    // 错误链检查
    _, err = fetchUser(-1)
    if errors.Is(err, ErrInvalidInput) {
        fmt.Println("输入验证错误:", err)
    }

    _, err = fetchUser(2000)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("资源未找到:", err)
    }

    // errors.As提取具体错误类型
    _, err = parseConfig("nonexistent.json")
    if err != nil {
        var pathErr *os.PathError
        if errors.As(err, &pathErr) {
            fmt.Printf("路径错误: %s\n", pathErr.Path)
        } else {
            fmt.Println("其他错误:", err)
        }
    }
}

11.2 自定义错误类型

package main

import (
    "fmt"
    "time"
)

// 自定义错误结构体
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证错误 [%s]: %s", e.Field, e.Message)
}

// 多错误聚合
type MultiError struct {
    Errors []error
}

func (me *MultiError) Error() string {
    if len(me.Errors) == 0 {
        return "无错误"
    }
    msg := fmt.Sprintf("共%d个错误:\n", len(me.Errors))
    for i, err := range me.Errors {
        msg += fmt.Sprintf("  %d. %s\n", i+1, err.Error())
    }
    return msg
}

func (me *MultiError) Add(err error) {
    me.Errors = append(me.Errors, err)
}

func (me *MultiError) HasErrors() bool {
    return len(me.Errors) > 0
}

// 带时间戳的错误
type TimedError struct {
    Err       error
    Timestamp time.Time
}

func (e *TimedError) Error() string {
    return fmt.Sprintf("[%s] %s", e.Timestamp.Format("15:04:05"), e.Err.Error())
}

func (e *TimedError) Unwrap() error {
    return e.Err
}

// 错误处理最佳实践
func validateUser(name, email string, age int) error {
    me := &MultiError{}

    if name == "" {
        me.Add(&ValidationError{Field: "name", Message: "不能为空"})
    }
    if email == "" {
        me.Add(&ValidationError{Field: "email", Message: "不能为空"})
    }
    if age < 0 || age > 150 {
        me.Add(&ValidationError{Field: "age", Message: "必须在0-150之间"})
    }

    if me.HasErrors() {
        return me
    }
    return nil
}

func main() {
    // 使用自定义错误
    if err := validateUser("", "", -1); err != nil {
        fmt.Println(err)
    }

    // 带时间戳的错误
    te := &TimedError{
        Err:       errors.New("数据库连接失败"),
        Timestamp: time.Now(),
    }
    fmt.Println(te)
}

// 需要导入 errors 包
import "errors"

12. 文件I/O

12.1 基本文件操作

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "path/filepath"
)

func main() {
    // 写入文件
    data := []byte("Hello, Go语言文件操作!\n第二行内容。\n")
    err := os.WriteFile("test.txt", data, 0644)
    if err != nil {
        fmt.Println("写入失败:", err)
        return
    }
    fmt.Println("文件写入成功")

    // 读取整个文件
    content, err := os.ReadFile("test.txt")
    if err != nil {
        fmt.Println("读取失败:", err)
        return
    }
    fmt.Printf("文件内容:\n%s", content)

    // 使用os.File进行更精细的控制
    file, err := os.Create("output.txt")
    if err != nil {
        fmt.Println("创建文件失败:", err)
        return
    }
    defer file.Close()

    // 写入字符串
    file.WriteString("写入字符串内容\n")
    file.Write([]byte("写入字节内容\n"))

    // 读取文件
    file2, err := os.Open("test.txt")
    if err != nil {
        fmt.Println("打开文件失败:", err)
        return
    }
    defer file2.Close()

    // 逐行读取
    scanner := bufio.NewScanner(file2)
    lineNum := 0
    for scanner.Scan() {
        lineNum++
        fmt.Printf("第%d行: %s\n", lineNum, scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Println("扫描错误:", err)
    }

    // 使用缓冲写入
    file3, _ := os.Create("buffered.txt")
    writer := bufio.NewWriter(file3)
    for i := 0; i < 10; i++ {
        writer.WriteString(fmt.Sprintf("第%d行\n", i))
    }
    writer.Flush() // 必须刷新缓冲区
    file3.Close()

    // 追加模式
    file4, _ := os.OpenFile("test.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    file4.WriteString("追加的内容\n")
    file4.Close()

    // 使用io.Copy复制文件
    src, _ := os.Open("test.txt")
    dst, _ := os.Create("copy.txt")
    bytesCopied, _ := io.Copy(dst, src)
    fmt.Printf("复制了 %d 字节\n", bytesCopied)
    src.Close()
    dst.Close()

    // 临时文件
    tmpFile, _ := os.CreateTemp("", "example-*.txt")
    tmpFile.WriteString("临时文件内容")
    fmt.Println("临时文件:", tmpFile.Name())
    tmpFile.Close()
    os.Remove(tmpFile.Name()) // 使用后删除

    // 清理
    os.Remove("test.txt")
    os.Remove("output.txt")
    os.Remove("buffered.txt")
    os.Remove("copy.txt")
}

12.2 目录操作

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    // 创建目录
    os.MkdirAll("testdir/subdir/deep", 0755)

    // 遍历目录
    filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }
        typ := "文件"
        if info.IsDir() {
            typ = "目录"
        }
        fmt.Printf("[%s] %s (%d bytes)\n", typ, path, info.Size())
        return nil
    })

    // 读取目录内容
    entries, _ := os.ReadDir(".")
    for _, entry := range entries {
        info, _ := entry.Info()
        fmt.Printf("名称: %s, 是目录: %v, 大小: %d\n",
            entry.Name(), entry.IsDir(), info.Size())
    }

    // 文件路径操作
    path := "/home/user/documents/report.pdf"
    fmt.Println("目录:", filepath.Dir(path))
    fmt.Println("文件名:", filepath.Base(path))
    fmt.Println("扩展名:", filepath.Ext(path))
    fmt.Println("绝对路径:", filepath.Abs(path))

    // 路径拼接
    joined := filepath.Join("home", "user", "documents", "file.txt")
    fmt.Println("拼接路径:", joined)

    // 清理
    os.RemoveAll("testdir")
}

12.3 文件信息与权限

package main

import (
    "fmt"
    "os"
)

func main() {
    // 获取文件信息
    info, err := os.Stat("main.go")
    if err != nil {
        if os.IsNotExist(err) {
            fmt.Println("文件不存在")
        }
        return
    }

    fmt.Println("文件名:", info.Name())
    fmt.Println("大小:", info.Size(), "字节")
    fmt.Println("权限:", info.Mode())
    fmt.Println("修改时间:", info.ModTime())
    fmt.Println("是目录:", info.IsDir())

    // 检查文件是否存在
    if _, err := os.Stat("nonexistent.txt"); os.IsNotExist(err) {
        fmt.Println("文件不存在")
    }

    // 修改权限
    os.Chmod("test.txt", 0755)

    // 创建符号链接
    os.Symlink("target.txt", "link.txt")
    os.Remove("link.txt")
}

13. HTTP服务开发

13.1 基本HTTP服务器

package main

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

// 基本处理器
func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "你好,世界!请求路径: %s\n", r.URL.Path)
}

// JSON响应
type Response struct {
    Message string      `json:"message"`
    Data    interface{} `json:"data"`
    Time    string      `json:"time"`
}

func apiHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")

    resp := Response{
        Message: "成功",
        Data:    map[string]string{"name": "Go", "version": "1.22"},
        Time:    time.Now().Format(time.RFC3339),
    }

    json.NewEncoder(w).Encode(resp)
}

// 处理不同HTTP方法
func methodHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        fmt.Fprintln(w, "GET请求")
    case http.MethodPost:
        fmt.Fprintln(w, "POST请求")
    case http.MethodPut:
        fmt.Fprintln(w, "PUT请求")
    case http.MethodDelete:
        fmt.Fprintln(w, "DELETE请求")
    default:
        http.Error(w, "不支持的方法", http.StatusMethodNotAllowed)
    }
}

// 中间件
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next(w, r)
        log.Printf("[%s] %s %s 耗时: %v",
            r.Method, r.URL.Path, r.RemoteAddr, time.Since(start))
    }
}

func corsMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
        next(w, r)
    }
}

func main() {
    // 使用默认路由器
    http.HandleFunc("/", helloHandler)
    http.HandleFunc("/api", apiHandler)
    http.HandleFunc("/methods", methodHandler)

    // 使用中间件
    http.HandleFunc("/logged", corsMiddleware(loggingMiddleware(helloHandler)))

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

13.2 HTTP客户端

package main

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

func main() {
    // 创建自定义客户端(带超时)
    client := &http.Client{
        Timeout: 10 * time.Second,
    }

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

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

    // POST请求(JSON)
    data := map[string]string{
        "name":  "张三",
        "email": "zhangsan@example.com",
    }
    jsonData, _ := json.Marshal(data)

    resp2, err := client.Post(
        "https://httpbin.org/post",
        "application/json",
        bytes.NewBuffer(jsonData),
    )
    if err != nil {
        fmt.Println("POST请求失败:", err)
        return
    }
    defer resp2.Body.Close()

    body2, _ := io.ReadAll(resp2.Body)
    fmt.Printf("\nPOST响应: %s\n", body2[:200])

    // 使用自定义Request
    req, _ := http.NewRequest("PUT", "https://httpbin.org/put", bytes.NewBuffer(jsonData))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer token123")

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

    body3, _ := io.ReadAll(resp3.Body)
    fmt.Printf("\nPUT响应: %s\n", body3[:200])
}

14. 数据库操作

14.1 使用database/sql

package main

import (
    "database/sql"
    "fmt"
    "log"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

// User模型
type User struct {
    ID        int
    Name      string
    Email     string
    Age       int
    CreatedAt time.Time
}

func main() {
    // 连接数据库
    dsn := "user:password@tcp(localhost:3306)/mydb?charset=utf8mb4&parseTime=true"
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        log.Fatal("连接数据库失败:", err)
    }
    defer db.Close()

    // 配置连接池
    db.SetMaxOpenConns(25)
    db.SetMaxIdleConns(5)
    db.SetConnMaxLifetime(5 * time.Minute)

    // 测试连接
    if err := db.Ping(); err != nil {
        log.Fatal("数据库Ping失败:", err)
    }
    fmt.Println("数据库连接成功")

    // 创建表
    createTable := `
    CREATE TABLE IF NOT EXISTS users (
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(100) NOT NULL,
        email VARCHAR(100) UNIQUE NOT NULL,
        age INT DEFAULT 0,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    )`
    _, err = db.Exec(createTable)
    if err != nil {
        log.Fatal("创建表失败:", err)
    }

    // 插入数据
    result, err := db.Exec(
        "INSERT INTO users (name, email, age) VALUES (?, ?, ?)",
        "张三", "zhangsan@example.com", 25,
    )
    if err != nil {
        log.Fatal("插入失败:", err)
    }
    id, _ := result.LastInsertId()
    fmt.Printf("插入成功,ID: %d\n", id)

    // 查询单行
    var user User
    err = db.QueryRow(
        "SELECT id, name, email, age, created_at FROM users WHERE id = ?", id,
    ).Scan(&user.ID, &user.Name, &user.Email, &user.Age, &user.CreatedAt)
    if err != nil {
        if err == sql.ErrNoRows {
            fmt.Println("未找到用户")
        } else {
            log.Fatal("查询失败:", err)
        }
    }
    fmt.Printf("查询结果: %+v\n", user)

    // 查询多行
    rows, err := db.Query("SELECT id, name, email, age FROM users WHERE age > ?", 18)
    if err != nil {
        log.Fatal("查询失败:", err)
    }
    defer rows.Close()

    var users []User
    for rows.Next() {
        var u User
        if err := rows.Scan(&u.ID, &u.Name, &u.Email, &u.Age); err != nil {
            log.Fatal("扫描失败:", err)
        }
        users = append(users, u)
    }
    if err := rows.Err(); err != nil {
        log.Fatal("遍历失败:", err)
    }
    fmt.Printf("查询到 %d 个用户\n", len(users))

    // 事务
    tx, err := db.Begin()
    if err != nil {
        log.Fatal("开启事务失败:", err)
    }

    _, err = tx.Exec("UPDATE users SET age = age + 1 WHERE name = ?", "张三")
    if err != nil {
        tx.Rollback()
        log.Fatal("更新失败:", err)
    }

    _, err = tx.Exec("INSERT INTO users (name, email, age) VALUES (?, ?, ?)",
        "李四", "lisi@example.com", 30)
    if err != nil {
        tx.Rollback()
        log.Fatal("插入失败:", err)
    }

    if err := tx.Commit(); err != nil {
        log.Fatal("提交事务失败:", err)
    }
    fmt.Println("事务提交成功")

    // 预编译语句(防止SQL注入)
    stmt, err := db.Prepare("SELECT id, name, email FROM users WHERE age > ?")
    if err != nil {
        log.Fatal("预编译失败:", err)
    }
    defer stmt.Close()

    rows2, _ := stmt.Query(20)
    defer rows2.Close()

    for rows2.Next() {
        var id, age int
        var name, email string
        rows2.Scan(&id, &name, &email)
        fmt.Printf("ID: %d, Name: %s, Email: %s\n", id, name, email)
    }
}

15. JSON处理

15.1 基本JSON操作

package main

import (
    "encoding/json"
    "fmt"
    "os"
    "time"
)

// 结构体标签
type User struct {
    ID        int       `json:"id"`
    Name      string    `json:"name"`
    Email     string    `json:"email"`
    Age       int       `json:"age,omitempty"`      // 零值时省略
    Password  string    `json:"-"`                   // 永不序列化
    CreatedAt time.Time `json:"created_at"`
    Tags      []string  `json:"tags,omitempty"`
    Address   *Address  `json:"address,omitempty"`   // 指针类型,nil时省略
}

type Address struct {
    City    string `json:"city"`
    Country string `json:"country"`
}

func main() {
    // 序列化(结构体 -> JSON)
    user := User{
        ID:        1,
        Name:      "张三",
        Email:     "zhangsan@example.com",
        Age:       25,
        Password:  "secret123", // 不会被序列化
        CreatedAt: time.Now(),
        Tags:      []string{"golang", "backend"},
        Address: &Address{
            City:    "北京",
            Country: "中国",
        },
    }

    // 格式化输出
    jsonData, err := json.MarshalIndent(user, "", "  ")
    if err != nil {
        fmt.Println("序列化失败:", err)
        return
    }
    fmt.Println("序列化结果:")
    fmt.Println(string(jsonData))

    // 反序列化(JSON -> 结构体)
    jsonStr := `{
        "id": 2,
        "name": "李四",
        "email": "lisi@example.com",
        "age": 30,
        "created_at": "2024-01-15T10:30:00Z",
        "tags": ["python", "data"]
    }`

    var user2 User
    err = json.Unmarshal([]byte(jsonStr), &user2)
    if err != nil {
        fmt.Println("反序列化失败:", err)
        return
    }
    fmt.Printf("\n反序列化结果: %+v\n", user2)

    // 未知结构的JSON(使用map)
    var unknown map[string]interface{}
    json.Unmarshal([]byte(jsonStr), &unknown)
    fmt.Println("\n未知结构:")
    for k, v := range unknown {
        fmt.Printf("  %s: %v (类型: %T)\n", k, v, v)
    }

    // JSON数组
    users := []User{
        {ID: 1, Name: "张三", Email: "zhangsan@example.com", Age: 25},
        {ID: 2, Name: "李四", Email: "lisi@example.com", Age: 30},
        {ID: 3, Name: "王五", Email: "wangwu@example.com", Age: 28},
    }
    jsonArray, _ := json.MarshalIndent(users, "", "  ")
    fmt.Println("\nJSON数组:")
    fmt.Println(string(jsonArray))

    // 流式编码/解码
    // 写入文件
    file, _ := os.Create("users.json")
    encoder := json.NewEncoder(file)
    encoder.SetIndent("", "  ")
    encoder.Encode(users)
    file.Close()

    // 从文件读取
    file2, _ := os.Open("users.json")
    var loadedUsers []User
    decoder := json.NewDecoder(file2)
    decoder.Decode(&loadedUsers)
    file2.Close()

    fmt.Printf("\n从文件加载了 %d 个用户\n", len(loadedUsers))

    // 自定义JSON序列化
    type Color struct {
        R, G, B uint8
    }

    // 自定义序列化
    func (c Color) MarshalJSON() ([]byte, error) {
        return json.Marshal(fmt.Sprintf("#%02x%02x%02x", c.R, c.G, c.B))
    }

    // 自定义反序列化
    func (c *Color) UnmarshalJSON(data []byte) error {
        var s string
        if err := json.Unmarshal(data, &s); err != nil {
            return err
        }
        _, err := fmt.Sscanf(s, "#%02x%02x%02x", &c.R, &c.G, &c.B)
        return err
    }

    red := Color{R: 255, G: 0, B: 0}
    colorJSON, _ := json.Marshal(red)
    fmt.Printf("\n自定义序列化: %s\n", colorJSON)

    os.Remove("users.json")
}

16. 测试与基准测试

16.1 单元测试

// calculator/calculator.go
package calculator

import (
    "errors"
    "math"
)

func Add(a, b float64) float64 {
    return a + b
}

func Subtract(a, b float64) float64 {
    return a - b
}

func Multiply(a, b float64) float64 {
    return a * b
}

func Divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

func Sqrt(x float64) (float64, error) {
    if x < 0 {
        return 0, errors.New("square root of negative number")
    }
    return math.Sqrt(x), nil
}
// calculator/calculator_test.go
package calculator

import (
    "math"
    "testing"
)

// 基本测试
func TestAdd(t *testing.T) {
    result := Add(2, 3)
    expected := 5.0
    if result != expected {
        t.Errorf("Add(2, 3) = %f; want %f", result, expected)
    }
}

// 表驱动测试
func TestDivide(t *testing.T) {
    tests := []struct {
        name     string
        a, b     float64
        expected float64
        wantErr  bool
    }{
        {"正常除法", 10, 3, 3.333333, false},
        {"除以零", 10, 0, 0, true},
        {"负数除法", -10, 2, -5, false},
        {"零除以数", 0, 5, 0, false},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result, err := Divide(tt.a, tt.b)
            if (err != nil) != tt.wantErr {
                t.Errorf("Divide(%f, %f) error = %v, wantErr %v",
                    tt.a, tt.b, err, tt.wantErr)
                return
            }
            if !tt.wantErr && math.Abs(result-tt.expected) > 0.0001 {
                t.Errorf("Divide(%f, %f) = %f; want %f",
                    tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

// 测试Sqrt
func TestSqrt(t *testing.T) {
    tests := []struct {
        input   float64
        want    float64
        wantErr bool
    }{
        {4, 2, false},
        {9, 3, false},
        {-1, 0, true},
        {0, 0, false},
    }

    for _, tt := range tests {
        got, err := Sqrt(tt.input)
        if (err != nil) != tt.wantErr {
            t.Errorf("Sqrt(%v) error = %v, wantErr %v", tt.input, err, tt.wantErr)
            continue
        }
        if !tt.wantErr && math.Abs(got-tt.want) > 1e-10 {
            t.Errorf("Sqrt(%v) = %v, want %v", tt.input, got, tt.want)
        }
    }
}

// 基准测试
func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(2.5, 3.7)
    }
}

func BenchmarkDivide(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Divide(100, 7)
    }
}

// 子基准测试
func BenchmarkDivide_Precision(b *testing.B) {
    benchmarks := []struct {
        name string
        a, b float64
    }{
        {"整数", 100, 7},
        {"小数", 3.14159, 2.71828},
        {"大数", 1e15, 3},
    }
    for _, bm := range benchmarks {
        b.Run(bm.name, func(b *testing.B) {
            for i := 0; i < b.N; i++ {
                Divide(bm.a, bm.b)
            }
        })
    }
}

运行测试:

# 运行所有测试
go test ./...

# 运行特定包的测试
go test ./calculator/

# 运行特定测试
go test -run TestDivide ./calculator/

# 显示详细输出
go test -v ./calculator/

# 运行基准测试
go test -bench=. ./calculator/

# 生成测试覆盖率
go test -cover ./calculator/
go test -coverprofile=coverage.out ./calculator/
go tool cover -html=coverage.out  # 浏览器查看覆盖率

# 模糊测试(Go 1.18+)
func FuzzDivide(f *testing.F) {
    f.Add(10.0, 3.0)
    f.Add(0.0, 1.0)
    f.Fuzz(func(t *testing.T, a, b float64) {
        result, err := Divide(a, b)
        if err != nil && b != 0 {
            t.Errorf("Divide(%f, %f) unexpected error: %v", a, b, err)
        }
        if err == nil && b != 0 {
            expected := a / b
            if math.Abs(result-expected) > 1e-10 {
                t.Errorf("Divide(%f, %f) = %f, want %f", a, b, result, expected)
            }
        }
    })
}

17. 依赖管理

17.1 Go Modules详解

# 初始化新项目
mkdir myproject && cd myproject
go mod init github.com/username/myproject

# 查看go.mod
cat go.mod
# module github.com/username/myproject
# go 1.22

# 添加依赖
go get github.com/gin-gonic/gin
go get github.com/sirupsen/logrus@v1.9.3

# 添加特定版本
go get github.com/gin-gonic/gin@v1.9.1

# 更新到最新版本
go get -u github.com/gin-gonic/gin

# 更新所有依赖
go get -u ./...

# 整理依赖
go mod tidy

# 查看依赖图
go mod graph

# 验证依赖完整性
go mod verify

# 生成vendor目录
go mod vendor

# 使用vendor构建
go build -mod=vendor ./...

# 查看可用版本
go list -m -versions github.com/gin-gonic/gin

17.2 go.sum文件

go.sum文件记录了每个依赖的加密哈希值,确保依赖的完整性和安全性:

github.com/gin-gonic/gin v1.9.1 h1:4idEAnCLz/...
github.com/gin-gonic/gin v1.9.1/go.mod h1:...

17.3 私有模块

# 配置私有模块
go env -w GOPRIVATE=github.com/mycompany/*

# 或者分别配置
go env -w GONOSUMCHECK=github.com/mycompany/*
go env -w GONOSUMDB=github.com/mycompany/*

# 使用私有仓库(需要配置git认证)
go get github.com/mycompany/private-repo

17.4 版本选择策略

// go.mod中的版本约束
require (
    // 精确版本
    github.com/pkg/errors v0.9.1

    // 语义化版本
    github.com/gin-gonic/gin v1.9.1

    // 主版本号(需要在import路径中包含)
    github.com/go-yaml/yaml/v3 v3.0.1
)

// replace替换(用于本地开发或fork)
replace (
    github.com/old/package => github.com/new/package v1.0.0
    github.com/local/package => ../local/package
)

// exclude排除特定版本
exclude github.com/broken/package v1.2.3

18. 常用标准库

18.1 fmt格式化

package main

import "fmt"

func main() {
    name := "张三"
    age := 25
    height := 175.5

    // Print系列
    fmt.Println("换行打印")
    fmt.Print("不换行")
    fmt.Printf("格式化: %s, %d岁, %.1fcm\n", name, age, height)

    // 格式化动词
    fmt.Printf("字符串: %s\n", name)      // 字符串
    fmt.Printf("整数: %d\n", age)          // 十进制整数
    fmt.Printf("二进制: %b\n", age)        // 二进制
    fmt.Printf("八进制: %o\n", age)        // 八进制
    fmt.Printf("十六进制: %x\n", age)      // 十六进制(小写)
    fmt.Printf("浮点数: %f\n", height)     // 浮点数
    fmt.Printf("科学计数: %e\n", height)   // 科学计数法
    fmt.Printf("布尔: %t\n", true)         // 布尔
    fmt.Printf("类型: %T\n", name)         // 类型
    fmt.Printf("值: %v\n", name)           // 值(默认格式)
    fmt.Printf("详细: %+v\n", struct{X int}{1}) // 包含字段名
    fmt.Printf("Go语法: %#v\n", name)      // Go语法表示
    fmt.Printf("指针: %p\n", &name)        // 指针地址

    // 宽度和精度
    fmt.Printf("[%10s]\n", "hello")     // 右对齐,宽度10
    fmt.Printf("[%-10s]\n", "hello")    // 左对齐,宽度10
    fmt.Printf("[%010d]\n", 42)         // 零填充,宽度10
    fmt.Printf("[%.3f]\n", 3.14159)     // 精度3位小数
    fmt.Printf("[%10.3f]\n", 3.14159)   // 宽度10,精度3

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

    // Errorf创建错误
    err := fmt.Errorf("用户 %s 不存在 (ID: %d)", name, 42)
    fmt.Println(err)
}

18.2 strings字符串处理

package main

import (
    "fmt"
    "strings"
)

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

    // 查找
    fmt.Println("包含Go:", strings.Contains(s, "Go"))
    fmt.Println("包含Rust:", strings.Contains(s, "Rust"))
    fmt.Println("前缀Hello:", strings.HasPrefix(s, "Hello"))
    fmt.Println("后缀World!:", strings.HasSuffix(s, "World!"))
    fmt.Println("第一次出现Hello:", strings.Index(s, "Hello"))
    fmt.Println("最后一次出现Hello:", strings.LastIndex(s, "Hello"))

    // 转换
    fmt.Println("大写:", strings.ToUpper("hello"))
    fmt.Println("小写:", strings.ToUpper("HELLO"))
    fmt.Println("标题:", strings.Title("hello world"))

    // 替换
    fmt.Println("替换:", strings.Replace("aabbaa", "aa", "xx", 1))
    fmt.Println("全部替换:", strings.ReplaceAll("aabbaa", "aa", "xx"))

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

    joined := strings.Join(parts, " | ")
    fmt.Println("连接:", joined)

    // 修剪
    fmt.Println("修剪空格:", strings.TrimSpace("  hello  "))
    fmt.Println("修剪字符:", strings.Trim("***hello***", "*"))
    fmt.Println("修剪左侧:", strings.TrimLeft("***hello***", "*"))
    fmt.Println("修剪右侧:", strings.TrimRight("***hello***", "*"))

    // 重复和比较
    fmt.Println("重复:", strings.Repeat("Go!", 3))
    fmt.Println("比较:", strings.Compare("abc", "abd")) // -1
    fmt.Println("相等:", strings.EqualFold("Go", "go")) // true(忽略大小写)

    // Reader
    reader := strings.NewReader("Hello, Reader!")
    buf := make([]byte, 5)
    n, _ := reader.Read(buf)
    fmt.Printf("读取了%d字节: %s\n", n, buf)
}

18.3 time时间处理

package main

import (
    "fmt"
    "time"
)

func main() {
    // 当前时间
    now := time.Now()
    fmt.Println("当前时间:", now)
    fmt.Println("年:", now.Year())
    fmt.Println("月:", now.Month())
    fmt.Println("日:", now.Day())
    fmt.Println("时:", now.Hour())
    fmt.Println("分:", now.Minute())
    fmt.Println("秒:", now.Second())
    fmt.Println("星期:", now.Weekday())

    // 时间格式化(Go使用特定时间 2006-01-02 15:04:05)
    fmt.Println("日期:", now.Format("2006-01-02"))
    fmt.Println("时间:", now.Format("15:04:05"))
    fmt.Println("完整:", now.Format("2006-01-02 15:04:05"))
    fmt.Println("RFC3339:", now.Format(time.RFC3339))

    // 解析时间字符串
    t, err := time.Parse("2006-01-02", "2024-01-15")
    if err != nil {
        fmt.Println("解析失败:", err)
    } else {
        fmt.Println("解析结果:", t)
    }

    // 时间运算
    tomorrow := now.Add(24 * time.Hour)
    fmt.Println("明天:", tomorrow.Format("2006-01-02"))

    lastWeek := now.AddDate(0, 0, -7)
    fmt.Println("上周:", lastWeek.Format("2006-01-02"))

    // 时间差
    diff := tomorrow.Sub(now)
    fmt.Println("时间差:", diff)
    fmt.Println("小时:", diff.Hours())
    fmt.Println("分钟:", diff.Minutes())

    // 时间比较
    fmt.Println("在明天之前:", now.Before(tomorrow))
    fmt.Println("在明天之后:", now.After(tomorrow))
    fmt.Println("相等:", now.Equal(now))

    // 定时器
    timer := time.NewTimer(2 * time.Second)
    fmt.Println("等待2秒...")
    <-timer.C
    fmt.Println("2秒已过")

    // 周期性定时器
    ticker := time.NewTicker(500 * time.Millisecond)
    go func() {
        for t := range ticker.C {
            fmt.Println("Tick:", t.Format("15:04:05"))
        }
    }()
    time.Sleep(2 * time.Second)
    ticker.Stop()
    fmt.Println("Ticker停止")
}

18.4 strconv类型转换

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 整数转字符串
    fmt.Println("Itoa:", strconv.Itoa(42))
    fmt.Println("FormatInt:", strconv.FormatInt(255, 16)) // 十六进制

    // 字符串转整数
    n, _ := strconv.Atoi("123")
    fmt.Println("Atoi:", n)

    n2, _ := strconv.ParseInt("ff", 16, 64)
    fmt.Println("ParseInt(十六进制):", n2)

    // 浮点数
    fmt.Println("Float:", strconv.FormatFloat(3.14159, 'f', 2, 64))
    f, _ := strconv.ParseFloat("3.14", 64)
    fmt.Println("ParseFloat:", f)

    // 布尔值
    fmt.Println("Bool:", strconv.FormatBool(true))
    b, _ := strconv.ParseBool("true")
    fmt.Println("ParseBool:", b)

    // 错误处理
    _, err := strconv.Atoi("abc")
    if err != nil {
        fmt.Println("转换错误:", err)
    }
}

18.5 sort排序

package main

import (
    "fmt"
    "sort"
)

func main() {
    // 基本排序
    ints := []int{5, 2, 6, 3, 1, 4}
    sort.Ints(ints)
    fmt.Println("整数排序:", ints)

    strings2 := []string{"banana", "apple", "cherry"}
    sort.Strings(strings2)
    fmt.Println("字符串排序:", strings2)

    // 自定义排序
    people := []struct {
        Name string
        Age  int
    }{
        {"张三", 25},
        {"李四", 30},
        {"王五", 20},
        {"赵六", 28},
    }

    // 按年龄排序
    sort.Slice(people, func(i, j int) bool {
        return people[i].Age < people[j].Age
    })
    fmt.Println("按年龄排序:", people)

    // 使用sort.Interface
    type PersonSlice []struct {
        Name string
        Age  int
    }

    func (p PersonSlice) Len() int           { return len(p) }
    func (p PersonSlice) Less(i, j int) bool { return p[i].Name < p[j].Name }
    func (p PersonSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

    sort.Sort(PersonSlice(people))
    fmt.Println("按姓名排序:", people)

    // 二分查找(需要先排序)
    sort.Ints(ints)
    idx := sort.SearchInts(ints, 3)
    fmt.Println("查找3的索引:", idx)

    // 反转
    sort.Sort(sort.Reverse(sort.IntSlice(ints)))
    fmt.Println("降序排序:", ints)
}

19. 实战:RESTful API服务

以下是一个完整的RESTful API服务实现,包含用户管理的增删改查功能:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "strconv"
    "strings"
    "sync"
    "time"
)

// ===== 数据模型 =====

type User struct {
    ID        int       `json:"id"`
    Name      string    `json:"name"`
    Email     string    `json:"email"`
    Age       int       `json:"age"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}

type APIResponse struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

// ===== 数据存储(内存模拟)=====

type UserStore struct {
    mu     sync.RWMutex
    users  map[int]*User
    nextID int
}

func NewUserStore() *UserStore {
    return &UserStore{
        users:  make(map[int]*User),
        nextID: 1,
    }
}

func (s *UserStore) Create(user *User) *User {
    s.mu.Lock()
    defer s.mu.Unlock()

    user.ID = s.nextID
    s.nextID++
    user.CreatedAt = time.Now()
    user.UpdatedAt = time.Now()

    s.users[user.ID] = user
    return user
}

func (s *UserStore) GetByID(id int) *User {
    s.mu.RLock()
    defer s.mu.RUnlock()
    return s.users[id]
}

func (s *UserStore) GetAll() []*User {
    s.mu.RLock()
    defer s.mu.RUnlock()

    users := make([]*User, 0, len(s.users))
    for _, u := range s.users {
        users = append(users, u)
    }
    return users
}

func (s *UserStore) Update(id int, update *User) *User {
    s.mu.Lock()
    defer s.mu.Unlock()

    existing, ok := s.users[id]
    if !ok {
        return nil
    }

    if update.Name != "" {
        existing.Name = update.Name
    }
    if update.Email != "" {
        existing.Email = update.Email
    }
    if update.Age > 0 {
        existing.Age = update.Age
    }
    existing.UpdatedAt = time.Now()

    return existing
}

func (s *UserStore) Delete(id int) bool {
    s.mu.Lock()
    defer s.mu.Unlock()

    if _, ok := s.users[id]; !ok {
        return false
    }
    delete(s.users, id)
    return true
}

// ===== HTTP处理器 =====

type UserHandler struct {
    store *UserStore
}

func NewUserHandler(store *UserStore) *UserHandler {
    return &UserHandler{store: store}
}

func (h *UserHandler) writeJSON(w http.ResponseWriter, code int, data interface{}) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(code)
    json.NewEncoder(w).Encode(data)
}

func (h *UserHandler) HandleUsers(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        h.listUsers(w, r)
    case http.MethodPost:
        h.createUser(w, r)
    default:
        h.writeJSON(w, http.StatusMethodNotAllowed, APIResponse{
            Code: 405, Message: "不支持的HTTP方法",
        })
    }
}

func (h *UserHandler) HandleUser(w http.ResponseWriter, r *http.Request) {
    // 从URL提取ID: /api/users/123
    parts := strings.Split(r.URL.Path, "/")
    if len(parts) < 4 {
        h.writeJSON(w, http.StatusBadRequest, APIResponse{
            Code: 400, Message: "无效的URL",
        })
        return
    }

    id, err := strconv.Atoi(parts[3])
    if err != nil {
        h.writeJSON(w, http.StatusBadRequest, APIResponse{
            Code: 400, Message: "无效的用户ID",
        })
        return
    }

    switch r.Method {
    case http.MethodGet:
        h.getUser(w, r, id)
    case http.MethodPut:
        h.updateUser(w, r, id)
    case http.MethodDelete:
        h.deleteUser(w, r, id)
    default:
        h.writeJSON(w, http.StatusMethodNotAllowed, APIResponse{
            Code: 405, Message: "不支持的HTTP方法",
        })
    }
}

func (h *UserHandler) listUsers(w http.ResponseWriter, r *http.Request) {
    users := h.store.GetAll()
    h.writeJSON(w, http.StatusOK, APIResponse{
        Code: 200, Message: "成功", Data: users,
    })
}

func (h *UserHandler) createUser(w http.ResponseWriter, r *http.Request) {
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        h.writeJSON(w, http.StatusBadRequest, APIResponse{
            Code: 400, Message: "无效的请求体",
        })
        return
    }

    // 验证
    if user.Name == "" || user.Email == "" {
        h.writeJSON(w, http.StatusBadRequest, APIResponse{
            Code: 400, Message: "姓名和邮箱不能为空",
        })
        return
    }

    created := h.store.Create(&user)
    h.writeJSON(w, http.StatusCreated, APIResponse{
        Code: 201, Message: "创建成功", Data: created,
    })
}

func (h *UserHandler) getUser(w http.ResponseWriter, r *http.Request, id int) {
    user := h.store.GetByID(id)
    if user == nil {
        h.writeJSON(w, http.StatusNotFound, APIResponse{
            Code: 404, Message: "用户不存在",
        })
        return
    }
    h.writeJSON(w, http.StatusOK, APIResponse{
        Code: 200, Message: "成功", Data: user,
    })
}

func (h *UserHandler) updateUser(w http.ResponseWriter, r *http.Request, id int) {
    var update User
    if err := json.NewDecoder(r.Body).Decode(&update); err != nil {
        h.writeJSON(w, http.StatusBadRequest, APIResponse{
            Code: 400, Message: "无效的请求体",
        })
        return
    }

    user := h.store.Update(id, &update)
    if user == nil {
        h.writeJSON(w, http.StatusNotFound, APIResponse{
            Code: 404, Message: "用户不存在",
        })
        return
    }

    h.writeJSON(w, http.StatusOK, APIResponse{
        Code: 200, Message: "更新成功", Data: user,
    })
}

func (h *UserHandler) deleteUser(w http.ResponseWriter, r *http.Request, id int) {
    if !h.store.Delete(id) {
        h.writeJSON(w, http.StatusNotFound, APIResponse{
            Code: 404, Message: "用户不存在",
        })
        return
    }
    h.writeJSON(w, http.StatusOK, APIResponse{
        Code: 200, Message: "删除成功",
    })
}

// ===== 中间件 =====

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        log.Printf("[%s] %s %s - %v", r.Method, r.URL.Path, r.RemoteAddr, time.Since(start))
    })
}

func recoveryMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                log.Printf("Panic恢复: %v", err)
                http.Error(w, "服务器内部错误", http.StatusInternalServerError)
            }
        }()
        next.ServeHTTP(w, r)
    })
}

func corsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

        if r.Method == "OPTIONS" {
            w.WriteHeader(http.StatusOK)
            return
        }

        next.ServeHTTP(w, r)
    })
}

// ===== 路由器 =====

type Router struct {
    userHandler *UserHandler
}

func NewRouter(userHandler *UserHandler) *Router {
    return &Router{userHandler: userHandler}
}

func (rt *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    path := r.URL.Path

    switch {
    case path == "/api/users":
        rt.userHandler.HandleUsers(w, r)
    case strings.HasPrefix(path, "/api/users/"):
        rt.userHandler.HandleUser(w, r)
    case path == "/health":
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
    default:
        http.NotFound(w, r)
    }
}

// ===== 主函数 =====

func main() {
    store := NewUserStore()
    handler := NewUserHandler(store)
    router := NewRouter(handler)

    // 添加中间件链
    var httpHandler http.Handler = router
    httpHandler = corsMiddleware(httpHandler)
    httpHandler = loggingMiddleware(httpHandler)
    httpHandler = recoveryMiddleware(httpHandler)

    // 创建服务器
    server := &http.Server{
        Addr:         ":8080",
        Handler:      httpHandler,
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
        IdleTimeout:  60 * time.Second,
    }

    fmt.Println("RESTful API服务启动在 http://localhost:8080")
    fmt.Println("API端点:")
    fmt.Println("  GET    /api/users       - 获取所有用户")
    fmt.Println("  POST   /api/users       - 创建用户")
    fmt.Println("  GET    /api/users/:id   - 获取单个用户")
    fmt.Println("  PUT    /api/users/:id   - 更新用户")
    fmt.Println("  DELETE /api/users/:id   - 删除用户")
    fmt.Println("  GET    /health          - 健康检查")

    log.Fatal(server.ListenAndServe())
}

测试API:

# 获取所有用户
curl http://localhost:8080/api/users

# 创建用户
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","email":"zhangsan@example.com","age":25}'

# 获取单个用户
curl http://localhost:8080/api/users/1

# 更新用户
curl -X PUT http://localhost:8080/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"张三丰","age":30}'

# 删除用户
curl -X DELETE http://localhost:8080/api/users/1

# 健康检查
curl http://localhost:8080/health

20. 实战:并发爬虫

以下是一个完整的并发网页爬虫实现:

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "regexp"
    "strings"
    "sync"
    "time"
)

// ===== 数据结构 =====

type CrawlResult struct {
    URL        string
    Title      string
    StatusCode int
    Links      []string
    Error      error
    Duration   time.Duration
}

type Crawler struct {
    maxWorkers    int
    maxDepth      int
    timeout       time.Duration
    visited       map[string]bool
    mu            sync.Mutex
    wg            sync.WaitGroup
    results       []CrawlResult
    resultsMu     sync.Mutex
    urlCh         chan crawlTask
    httpClient    *http.Client
    allowedDomain string
}

type crawlTask struct {
    url   string
    depth int
}

// ===== 爬虫核心 =====

func NewCrawler(maxWorkers, maxDepth int, timeout time.Duration) *Crawler {
    return &Crawler{
        maxWorkers: maxWorkers,
        maxDepth:   maxDepth,
        timeout:    timeout,
        visited:    make(map[string]bool),
        urlCh:      make(chan crawlTask, maxWorkers*2),
        httpClient: &http.Client{
            Timeout: timeout,
            CheckRedirect: func(req *http.Request, via []*http.Request) error {
                if len(via) >= 5 {
                    return fmt.Errorf("重定向次数过多")
                }
                return nil
            },
        },
    }
}

func (c *Crawler) isVisited(urlStr string) bool {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.visited[urlStr]
}

func (c *Crawler) markVisited(urlStr string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.visited[urlStr] = true
}

func (c *Crawler) addResult(result CrawlResult) {
    c.resultsMu.Lock()
    defer c.resultsMu.Unlock()
    c.results = append(c.results, result)
}

func (c *Crawler) fetch(ctx context.Context, urlStr string) CrawlResult {
    start := time.Now()
    result := CrawlResult{URL: urlStr}

    req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlStr, nil)
    if err != nil {
        result.Error = fmt.Errorf("创建请求失败: %w", err)
        result.Duration = time.Since(start)
        return result
    }
    req.Header.Set("User-Agent", "GoCrawler/1.0")

    resp, err := c.httpClient.Do(req)
    if err != nil {
        result.Error = fmt.Errorf("请求失败: %w", err)
        result.Duration = time.Since(start)
        return result
    }
    defer resp.Body.Close()

    result.StatusCode = resp.StatusCode
    result.Duration = time.Since(start)

    // 只处理HTML响应
    contentType := resp.Header.Get("Content-Type")
    if !strings.Contains(contentType, "text/html") {
        return result
    }

    body, err := io.ReadAll(io.LimitReader(resp.Body, 10*1024*1024)) // 限制10MB
    if err != nil {
        result.Error = fmt.Errorf("读取响应失败: %w", err)
        return result
    }

    html := string(body)

    // 提取标题
    titleRe := regexp.MustCompile(`(?i)<title>(.*?)</title>`)
    if matches := titleRe.FindStringSubmatch(html); len(matches) > 1 {
        result.Title = strings.TrimSpace(matches[1])
    }

    // 提取链接
    linkRe := regexp.MustCompile(`(?i)href=["'](.*?)["']`)
    matches := linkRe.FindAllStringSubmatch(html, -1)
    seen := make(map[string]bool)
    for _, match := range matches {
        if len(match) > 1 {
            link := match[1]
            // 解析相对URL
            parsedBase, _ := url.Parse(urlStr)
            parsedLink, _ := url.Parse(link)
            resolved := parsedBase.ResolveReference(parsedLink)
            resolved.Fragment = "" // 去除锚点

            resolvedStr := resolved.String()
            if !seen[resolvedStr] && (resolved.Scheme == "http" || resolved.Scheme == "https") {
                seen[resolvedStr] = true
                result.Links = append(result.Links, resolvedStr)
            }
        }
    }

    return result
}

func (c *Crawler) worker(ctx context.Context) {
    defer c.wg.Done()

    for task := range c.urlCh {
        select {
        case <-ctx.Done():
            return
        default:
        }

        if c.isVisited(task.url) {
            continue
        }
        c.markVisited(task.url)

        fmt.Printf("[深度%d] 正在爬取: %s\n", task.depth, task.url)
        result := c.fetch(ctx, task.url)
        c.addResult(result)

        if result.Error != nil {
            fmt.Printf("  ✗ 错误: %v\n", result.Error)
            continue
        }

        fmt.Printf("  ✓ 状态: %d, 标题: %s, 耗时: %v, 链接数: %d\n",
            result.StatusCode, result.Title, result.Duration, len(result.Links))

        // 如果未达到最大深度,继续爬取子链接
        if task.depth < c.maxDepth {
            for _, link := range result.Links {
                if !c.isVisited(link) {
                    c.wg.Add(1)
                    go func(l string) {
                        defer c.wg.Done()
                        select {
                        case c.urlCh <- crawlTask{url: l, depth: task.depth + 1}:
                        case <-ctx.Done():
                        }
                    }(link)
                }
            }
        }
    }
}

func (c *Crawler) Crawl(ctx context.Context, startURL string) []CrawlResult {
    // 解析起始URL的域名
    parsed, err := url.Parse(startURL)
    if err != nil {
        return nil
    }
    c.allowedDomain = parsed.Host

    // 启动worker
    for i := 0; i < c.maxWorkers; i++ {
        c.wg.Add(1)
        go c.worker(ctx)
    }

    // 发送起始URL
    c.wg.Add(1)
    go func() {
        defer c.wg.Done()
        c.urlCh <- crawlTask{url: startURL, depth: 0}
    }()

    // 等待所有任务完成
    c.wg.Wait()
    close(c.urlCh)

    return c.results
}

// ===== 报告生成 =====

func generateReport(results []CrawlResult) string {
    var sb strings.Builder

    sb.WriteString("=== 爬虫报告 ===\n\n")
    sb.WriteString(fmt.Sprintf("总计爬取: %d 个页面\n", len(results)))

    successCount := 0
    errorCount := 0
    var totalDuration time.Duration

    for _, r := range results {
        if r.Error != nil {
            errorCount++
        } else {
            successCount++
        }
        totalDuration += r.Duration
    }

    sb.WriteString(fmt.Sprintf("成功: %d, 失败: %d\n", successCount, errorCount))
    sb.WriteString(fmt.Sprintf("总耗时: %v\n\n", totalDuration))

    sb.WriteString("=== 详细结果 ===\n\n")
    for i, r := range results {
        sb.WriteString(fmt.Sprintf("%d. %s\n", i+1, r.URL))
        if r.Title != "" {
            sb.WriteString(fmt.Sprintf("   标题: %s\n", r.Title))
        }
        sb.WriteString(fmt.Sprintf("   状态: %d\n", r.StatusCode))
        sb.WriteString(fmt.Sprintf("   耗时: %v\n", r.Duration))
        if r.Error != nil {
            sb.WriteString(fmt.Sprintf("   错误: %v\n", r.Error))
        }
        if len(r.Links) > 0 {
            sb.WriteString(fmt.Sprintf("   发现链接: %d 个\n", len(r.Links)))
        }
        sb.WriteString("\n")
    }

    return sb.String()
}

// ===== 主函数 =====

func main() {
    if len(os.Args) < 2 {
        fmt.Println("用法: go run crawler.go <URL> [最大深度] [并发数]")
        fmt.Println("示例: go run crawler.go https://example.com 2 5")
        return
    }

    startURL := os.Args[1]
    maxDepth := 1
    maxWorkers := 5

    if len(os.Args) > 2 {
        fmt.Sscanf(os.Args[2], "%d", &maxDepth)
    }
    if len(os.Args) > 3 {
        fmt.Sscanf(os.Args[3], "%d", &maxWorkers)
    }

    fmt.Printf("开始爬取: %s\n", startURL)
    fmt.Printf("最大深度: %d, 并发数: %d\n\n", maxDepth, maxWorkers)

    // 创建带超时的上下文
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
    defer cancel()

    // 创建爬虫并开始爬取
    crawler := NewCrawler(maxWorkers, maxDepth, 10*time.Second)
    results := crawler.Crawl(ctx, startURL)

    // 生成报告
    report := generateReport(results)
    fmt.Println(report)

    // 保存报告到文件
    reportFile := "crawl_report.txt"
    os.WriteFile(reportFile, []byte(report), 0644)
    fmt.Printf("报告已保存到: %s\n", reportFile)
}

运行爬虫:

# 基本用法
go run crawler.go https://example.com

# 指定深度和并发数
go run crawler.go https://example.com 3 10

# 编译后运行
go build -o crawler crawler.go
./crawler https://example.com 2 5

21. 部署与优化

21.1 交叉编译

# 查看支持的目标平台
go tool dist list

# 编译为Linux二进制(在macOS上)
GOOS=linux GOARCH=amd64 go build -o myapp-linux main.go

# 编译为Windows二进制
GOOS=windows GOARCH=amd64 go build -o myapp.exe main.go

# 编译为ARM架构(如树莓派)
GOOS=linux GOARCH=arm64 go build -o myapp-arm64 main.go

# 静态编译(无CGO依赖)
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags '-s -w' -o myapp-static main.go

21.2 优化编译

# 去除调试信息,减小二进制体积
go build -ldflags '-s -w' -o myapp main.go

# -s: 去除符号表
# -w: 去除DWARF调试信息

# 查看二进制大小
ls -lh myapp

# 使用upx压缩(可选)
# upx --best myapp

21.3 Docker部署

# 多阶段构建
FROM golang:1.22-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-s -w' -o main .

# 最终镜像
FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
ENV TZ=Asia/Shanghai

WORKDIR /root/
COPY --from=builder /app/main .

EXPOSE 8080
CMD ["./main"]

构建和运行:

# 构建镜像
docker build -t myapp:latest .

# 运行容器
docker run -d -p 8080:8080 --name myapp myapp:latest

# 查看日志
docker logs -f myapp

21.4 性能优化

1. 内存优化

// 预分配切片容量
// 不好的写法
var items []Item
for _, data := range rawData {
    items = append(items, process(data))
}

// 好的写法
items := make([]Item, 0, len(rawData))
for _, data := range rawData {
    items = append(items, process(data))
}

// 使用sync.Pool复用对象
var bufferPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 4096)
    },
}

func processRequest(data []byte) {
    buf := bufferPool.Get().([]byte)
    defer bufferPool.Put(buf)
    // 使用buf处理数据...
}

// 避免不必要的内存分配
// 不好的写法:每次循环创建新字符串
for i := 0; i < 1000; i++ {
    s := fmt.Sprintf("item-%d", i)
    process(s)
}

// 好的写法:使用strings.Builder
var builder strings.Builder
for i := 0; i < 1000; i++ {
    builder.Reset()
    builder.WriteString("item-")
    builder.WriteString(strconv.Itoa(i))
    process(builder.String())
}

2. 并发优化

// 控制goroutine数量
func processWithLimit(items []Item, maxWorkers int) []Result {
    results := make([]Result, len(items))
    sem := make(chan struct{}, maxWorkers)
    var wg sync.WaitGroup

    for i, item := range items {
        wg.Add(1)
        sem <- struct{}{} // 获取信号量
        go func(idx int, it Item) {
            defer wg.Done()
            defer func() { <-sem }() // 释放信号量
            results[idx] = process(it)
        }(i, item)
    }

    wg.Wait()
    return results
}

// 使用errgroup管理并发错误
import "golang.org/x/sync/errgroup"

func fetchAll(urls []string) ([]string, error) {
    results := make([]string, len(urls))
    g, ctx := errgroup.WithContext(context.Background())

    for i, u := range urls {
        i, u := i, u
        g.Go(func() error {
            select {
            case <-ctx.Done():
                return ctx.Err()
            default:
            }
            resp, err := http.Get(u)
            if err != nil {
                return err
            }
            defer resp.Body.Close()
            body, _ := io.ReadAll(resp.Body)
            results[i] = string(body)
            return nil
        })
    }

    if err := g.Wait(); err != nil {
        return nil, err
    }
    return results, nil
}

3. 使用pprof进行性能分析

package main

import (
    "net/http"
    _ "net/http/pprof"
    "log"
)

func main() {
    // 在单独的端口启动pprof
    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()

    // 你的应用代码...
    select {}
}
# CPU分析
go tool pprof http://localhost:60/debug/pprof/profile?seconds=30

# 内存分析
go tool pprof http://localhost:60/debug/pprof/heap

# goroutine分析
go tool pprof http://localhost:60/debug/pprof/goroutine

# 在交互模式中
(pprof) top
(pprof) list functionName
(pprof) web  # 生成SVG图(需要安装graphviz)

4. 编译优化技巧

# 使用编译器优化
go build -gcflags='-m -l' main.go  # 查看逃逸分析
go build -gcflags='-B' main.go     # 禁用边界检查(谨慎使用)

# 分析二进制
go tool nm myapp | grep main       # 查看符号
go tool objdump -S myapp           # 反汇编

21.5 监控与日志

package main

import (
    "log/slog"
    "os"
    "time"
)

func main() {
    // 使用slog结构化日志(Go 1.21+)
    logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelDebug,
    }))

    logger.Info("服务器启动",
        "port", 8080,
        "env", "production",
    )

    logger.Error("数据库连接失败",
        "error", "connection refused",
        "retry_in", 5*time.Second,
    )

    // 带上下文的logger
    requestLogger := logger.With(
        "request_id", "abc-123",
        "user_id", 42,
    )
    requestLogger.Info("处理请求", "path", "/api/users")
}

21.6 优雅关闭

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        time.Sleep(2 * time.Second) // 模拟处理
        fmt.Fprintln(w, "Hello!")
    })

    server := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }

    // 启动服务器
    go func() {
        log.Println("服务器启动在 :8080")
        if err := server.ListenAndServe(); err != http.ErrServerClosed {
            log.Fatal("服务器异常:", err)
        }
    }()

    // 监听系统信号
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit

    log.Println("收到关闭信号,正在优雅关闭...")

    // 给现有请求30秒的完成时间
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    if err := server.Shutdown(ctx); err != nil {
        log.Fatal("关闭失败:", err)
    }

    log.Println("服务器已安全关闭")
}

总结

本教程从Go语言的历史背景出发,系统性地介绍了Go语言的核心知识体系:

  1. 基础语法:数据类型、变量常量、控制流、函数方法等构成Go语言的基石。
  2. 数据结构:数组、切片、映射、结构体和接口是Go程序中数据组织的核心方式。
  3. 并发编程:goroutine和channel是Go语言最强大的特性,使得并发编程简单而高效。
  4. 工程实践:包管理、错误处理、测试、依赖管理等是构建大型Go项目的关键能力。
  5. 应用开发:HTTP服务、数据库操作、JSON处理等是Web开发的日常需求。
  6. 实战项目:RESTful API服务和并发爬虫展示了Go语言在真实场景中的应用。
  7. 部署优化:交叉编译、Docker部署、性能分析等帮助你将Go应用推向生产环境。

Go语言的学习曲线相对平缓,但它的并发模型和工程哲学值得深入理解。建议读者在学习过程中多动手实践,通过实际项目加深对Go语言的理解。随着Go语言生态的不断壮大,掌握Go语言将为你的职业生涯增添一项重要技能。


参考资料


本教程由AI生成,内容原创,可自由使用和分享。

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录