Go语言从入门到精通:2026年最新版完全指南
·
前言
Go(又称Golang)是由Google开发的开源编程语言,自2009年首次发布以来,凭借其简洁性、高性能和出色的并发支持,已成为云原生应用、微服务架构和系统编程的首选语言。截至2026年,Go 1.25版本带来了泛型完善、性能优化和现代化工具链的重大改进。本文将带你全面掌握Go的核心概念、语法特性、最佳实践和高级功能。
第一章:Go概述与核心概念
1.1 什么是Go?
Go是一种静态类型、编译型的编程语言,由Robert Griesemer、Rob Pike和Ken Thompson在Google开发。它结合了C语言的性能、Python的简洁性和现代语言的安全特性。
核心特点:
- 简洁性:语法简单,关键字少(仅25个),学习曲线平缓
- 高性能:编译为机器码,执行速度快,内存占用低
- 并发支持:goroutine和channel提供轻量级并发模型
- 垃圾回收:自动内存管理,减少内存泄漏风险
- 跨平台:支持Windows、Linux、macOS、ARM等多平台编译
- 标准库丰富:内置HTTP、JSON、加密、测试等强大功能
- 快速编译:增量编译,大型项目也能快速构建
- 工具链完善:go fmt、go vet、go test等内置工具
- 云原生友好:Docker、Kubernetes等基础设施均用Go编写
1.2 Go版本演进
| 版本 | 发布年份 | 主要特性 |
|---|---|---|
| Go 1.0 | 2012 | 基础语法、goroutine、channel |
| Go 1.4 | 2014 | 自举编译器(Go编写Go编译器) |
| Go 1.5 | 2015 | 并发垃圾回收、vendor支持 |
| Go 1.8 | 2017 | 插件支持、HTTP/2服务器推送 |
| Go 1.11 | 2018 | 模块支持(go mod)、WebAssembly |
| Go 1.13 | 2019 | 错误包装、数字字面量改进 |
| Go 1.16 | 2021 | 嵌入文件、io/fs接口 |
| Go 1.18 | 2022 | 泛型支持、工作区模式 |
| Go 1.20 | 2023 | 取消context、profile-guided优化 |
| Go 1.22 | 2024 | 循环变量捕获修复、range-over-func |
| Go 1.23 | 2024 | 迭代器、切片到数组转换 |
| Go 1.24 | 2025 | 异步函数、更好的错误处理 |
| Go 1.25 | 2026 | 泛型完善、性能优化、AI工具集成 |
当前推荐版本:Go 1.25 (2026年)
1.3 Go应用领域
- Web后端:API服务、微服务、RESTful服务
- 云原生:Kubernetes、Docker、Prometheus等基础设施
- DevOps工具:Terraform、Helm、Vault等
- 命令行工具:高效、单二进制文件分发
- 数据处理:ETL、批处理、实时流处理
- 网络编程:TCP/UDP服务器、代理、负载均衡
- 区块链:以太坊、Cosmos等区块链项目
- 嵌入式系统:IoT设备、边缘计算
第二章:环境准备与安装
2.1 系统要求
硬件要求:
- CPU:至少1 GHz
- 内存:至少1 GB(开发环境)
- 磁盘:至少2 GB可用空间
软件依赖:
- 操作系统:Windows 10+、Linux、macOS 12+
- Git(用于模块管理)
2.2 安装方法
Windows安装
# 使用winget(推荐)
winget install GoLang.Go
# 使用Chocolatey
choco install golang
# 验证安装
go version
macOS安装
# 使用Homebrew(推荐)
brew install go
# 使用安装包
# 下载 .pkg from https://golang.org/dl/
# 验证安装
go version
Linux安装 (Ubuntu/Debian)
# 使用官方包
wget https://go.dev/dl/go1.25.0.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.25.0.linux-amd64.tar.gz
# 添加到PATH
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
# 验证安装
go version
2.3 开发工具
IDE选择
- Visual Studio Code:配合Go扩展,轻量级且功能强大
- GoLand:JetBrains出品的专业Go IDE
- Vim/Neovim:配合vim-go插件
- Emacs:配合go-mode
项目创建
# 创建新项目
mkdir myproject
cd myproject
go mod init myproject
# 创建main.go
cat > main.go << EOF
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
EOF
# 运行项目
go run main.go
# 构建项目
go build
# 安装项目(生成可执行文件到GOPATH/bin)
go install
2.4 第一个Go程序
// main.go
package main
import (
"fmt"
"os"
)
func main() {
// 基本输出
fmt.Println("Hello, World!")
// 读取命令行参数
if len(os.Args) > 1 {
name := os.Args[1]
fmt.Printf("Hello, %s!\n", name)
} else {
fmt.Println("Please provide a name as argument")
}
}
运行程序:
# 初始化模块
go mod init hello
# 运行程序
go run main.go Alice
# 构建可执行文件
go build -o hello main.go
./hello Bob
# 交叉编译
GOOS=linux GOARCH=amd64 go build -o hello-linux main.go
GOOS=windows GOARCH=amd64 go build -o hello.exe main.go
第三章:Go基础语法
3.1 基本语法结构
包和导入
// 文件必须属于某个包
package main // main包用于可执行程序
// 导入标准库
import (
"fmt"
"os"
"strings"
)
// 导入第三方包
import (
"github.com/gin-gonic/gin"
)
// 点导入(不推荐)
import . "fmt" // 直接使用Println而不是fmt.Println
// 别名导入
import (
g "github.com/gin-gonic/gin"
json "encoding/json"
)
// 空导入(仅执行init函数)
import _ "net/http/pprof"
注释和文档
// 单行注释
/*
多行注释
*/
// Package comment describes the package.
package main
// ExportedFunction does something important.
// It takes a parameter and returns a result.
// Example:
// result := ExportedFunction("input")
// fmt.Println(result)
func ExportedFunction(param string) string {
return "processed: " + param
}
// unexportedFunction is not exported (starts with lowercase).
func unexportedFunction() {
// Internal implementation
}
3.2 变量和数据类型
基本数据类型
package main
import "fmt"
func main() {
// 整数类型
var int8Var int8 = 127
var int16Var int16 = 32767
var int32Var int32 = 2147483647
var int64Var int64 = 9223372036854775807
// 无符号整数
var uint8Var uint8 = 255
var uint16Var uint16 = 65535
var uint32Var uint32 = 4294967295
var uint64Var uint64 = 18446744073709551615
// 浮点类型
var float32Var float32 = 3.14
var float64Var float64 = 3.141592653589793
// 复数类型
var complex64Var complex64 = 1 + 2i
var complex128Var complex128 = 3 + 4i
// 字符串
var stringVar string = "Hello, World!"
var rawString string = `This is a raw string
that spans multiple lines
with "quotes" included.`
// 布尔类型
var boolVar bool = true
// 字节和符文
var byteVar byte = 'A' // byte is alias for uint8
var runeVar rune = '中' // rune is alias for int32
fmt.Println(int8Var, int16Var, int32Var, int64Var)
fmt.Println(uint8Var, uint16Var, uint32Var, uint64Var)
fmt.Println(float32Var, float64Var)
fmt.Println(complex64Var, complex128Var)
fmt.Println(stringVar, rawString)
fmt.Println(boolVar)
fmt.Println(byteVar, runeVar)
}
变量声明和初始化
package main
import "fmt"
func main() {
// 完整声明
var name string = "Alice"
var age int = 25
var salary float64 = 75000.50
// 类型推断
var city = "New York" // string
var population = 8400000 // int
// 短变量声明(仅在函数内使用)
country := "USA"
continent := "North America"
// 多变量声明
var firstName, lastName string = "John", "Doe"
x, y := 10, 20
a, b, c := true, 3.14, "hello"
// 批量声明
var (
id int
status string
created bool
)
// 零值初始化
var zeroInt int // 0
var zeroString string // ""
var zeroBool bool // false
var zeroFloat float64 // 0.0
fmt.Println(name, age, salary)
fmt.Println(city, population)
fmt.Println(country, continent)
fmt.Println(firstName, lastName)
fmt.Println(x, y, a, b, c)
fmt.Println(id, status, created)
fmt.Println(zeroInt, zeroString, zeroBool, zeroFloat)
}
常量
package main
import "fmt"
func main() {
// 基本常量
const pi = 3.14159
const appName = "MyApp"
const maxRetries = 3
// 显式类型常量
const timeoutSeconds int = 30
const debugMode bool = true
// 批量常量
const (
StatusPending = "pending"
StatusActive = "active"
StatusClosed = "closed"
)
// iota枚举
const (
Red = iota // 0
Green // 1
Blue // 2
)
const (
_ = iota // 忽略第一个值
KB = 1 << (10 * iota) // 1024
MB // 1048576
GB // 1073741824
TB // 1099511627776
)
fmt.Println(pi, appName, maxRetries)
fmt.Println(timeoutSeconds, debugMode)
fmt.Println(StatusPending, StatusActive, StatusClosed)
fmt.Println(Red, Green, Blue)
fmt.Println(KB, MB, GB, TB)
}
3.3 运算符和表达式
算术运算符
package main
import "fmt"
func main() {
a, b := 10, 3
fmt.Println(a + b) // 13
fmt.Println(a - b) // 7
fmt.Println(a * b) // 30
fmt.Println(a / b) // 3 (整数除法)
fmt.Println(a % b) // 1 (取余)
// 复合赋值
x := 5
x += 3 // x = 8
x -= 2 // x = 6
x *= 4 // x = 24
x /= 3 // x = 8
x %= 5 // x = 3
fmt.Println(x)
// 递增/递减(Go没有++/--作为表达式)
y := 10
y++ // y = 11
y-- // y = 10
fmt.Println(y)
}
比较和逻辑运算符
package main
import "fmt"
func main() {
x, y := 5, 10
// 比较运算符
fmt.Println(x == y) // false
fmt.Println(x != y) // true
fmt.Println(x < y) // true
fmt.Println(x >= y) // false
// 逻辑运算符
condition1, condition2 := true, false
fmt.Println(condition1 && condition2) // false
fmt.Println(condition1 || condition2) // true
fmt.Println(!condition1) // false
// 位运算符
a, b := 12, 10 // 1100, 1010
fmt.Printf("%b & %b = %b\n", a, b, a&b) // 1000 (8)
fmt.Printf("%b | %b = %b\n", a, b, a|b) // 1110 (14)
fmt.Printf("%b ^ %b = %b\n", a, b, a^b) // 0110 (6)
fmt.Printf("~%b = %b\n", a, ^a) // 取反
fmt.Printf("%b << 2 = %b\n", a, a<<2) // 110000 (48)
fmt.Printf("%b >> 2 = %b\n", a, a>>2) // 0011 (3)
}
3.4 控制结构
条件语句
package main
import "fmt"
func main() {
// if语句
score := 85
if score >= 90 {
fmt.Println("Grade: A")
} else if score >= 80 {
fmt.Println("Grade: B")
} else if score >= 70 {
fmt.Println("Grade: C")
} else {
fmt.Println("Grade: F")
}
// if with initialization
if age := 25; age >= 18 {
fmt.Println("Adult")
} else {
fmt.Println("Minor")
}
// switch语句
day := "Monday"
switch day {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
fmt.Println("Weekday")
case "Saturday", "Sunday":
fmt.Println("Weekend")
default:
fmt.Println("Invalid day")
}
// switch with initialization
switch hour := 14; {
case hour < 12:
fmt.Println("Morning")
case hour < 18:
fmt.Println("Afternoon")
default:
fmt.Println("Evening")
}
// type switch
var value interface{} = "hello"
switch v := value.(type) {
case string:
fmt.Printf("String: %s\n", v)
case int:
fmt.Printf("Integer: %d\n", v)
case bool:
fmt.Printf("Boolean: %t\n", v)
default:
fmt.Println("Unknown type")
}
}
循环语句
package main
import "fmt"
func main() {
// for循环(Go只有for,没有while)
for i := 0; i < 5; i++ {
fmt.Printf("Iteration %d\n", i)
}
// while风格循环
count := 0
for count < 3 {
fmt.Printf("Count: %d\n", count)
count++
}
// 无限循环
sum := 0
for {
sum++
if sum >= 10 {
break
}
}
fmt.Printf("Sum: %d\n", sum)
// range循环(遍历集合)
fruits := []string{"apple", "banana", "orange"}
// 只获取值
for _, fruit := range fruits {
fmt.Println(fruit)
}
// 获取索引和值
for index, fruit := range fruits {
fmt.Printf("Index %d: %s\n", index, fruit)
}
// 遍历map
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Carol": 35,
}
for name, age := range ages {
fmt.Printf("%s is %d years old\n", name, age)
}
// 遍历字符串(按rune)
text := "Hello 世界"
for i, char := range text {
fmt.Printf("Position %d: %c (U+%04X)\n", i, char, char)
}
// continue和break
for i := 0; i < 10; i++ {
if i == 3 {
continue // 跳过当前迭代
}
if i == 7 {
break // 退出循环
}
fmt.Println(i)
}
// 带标签的break/continue
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break outer // 跳出外层循环
}
fmt.Printf("(%d, %d)\n", i, j)
}
}
}
第四章:复合数据类型
4.1 数组和切片
数组
package main
import "fmt"
func main() {
// 固定长度数组
var numbers [5]int
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
// 初始化数组
letters := [3]string{"a", "b", "c"}
primes := [...]int{2, 3, 5, 7, 11} // 编译器推断长度
// 多维数组
matrix := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
fmt.Println(numbers)
fmt.Println(letters)
fmt.Println(primes)
fmt.Println(matrix)
// 数组长度
fmt.Printf("Numbers length: %d\n", len(numbers))
fmt.Printf("Letters length: %d\n", len(letters))
// 数组是值类型(复制整个数组)
original := [3]int{1, 2, 3}
copy := original
copy[0] = 999
fmt.Println("Original:", original) // [1 2 3]
fmt.Println("Copy:", copy) // [999 2 3]
}
切片
package main
import "fmt"
func main() {
// 从数组创建切片
numbers := [5]int{1, 2, 3, 4, 5}
slice1 := numbers[1:4] // [2 3 4]
slice2 := numbers[:3] // [1 2 3]
slice3 := numbers[2:] // [3 4 5]
// 直接创建切片
fruits := []string{"apple", "banana", "orange"}
emptySlice := []int{} // 空切片
// 使用make创建切片
scores := make([]int, 3) // 长度3,容量3
buffer := make([]byte, 0, 1024) // 长度0,容量1024
fmt.Println(slice1, slice2, slice3)
fmt.Println(fruits, emptySlice)
fmt.Println(scores, buffer)
// 切片操作
data := []int{1, 2, 3, 4, 5}
// 追加元素
data = append(data, 6)
data = append(data, 7, 8, 9)
// 追加另一个切片
moreData := []int{10, 11, 12}
data = append(data, moreData...)
// 复制切片
copied := make([]int, len(data))
copy(copied, data)
// 切片容量和长度
fmt.Printf("Length: %d, Capacity: %d\n", len(data), cap(data))
// 动态扩容
small := make([]int, 0, 2)
fmt.Printf("Initial: len=%d, cap=%d\n", len(small), cap(small))
for i := 0; i < 10; i++ {
small = append(small, i)
fmt.Printf("After append %d: len=%d, cap=%d\n", i, len(small), cap(small))
}
// 切片是引用类型
originalSlice := []int{1, 2, 3}
modifiedSlice := originalSlice
modifiedSlice[0] = 999
fmt.Println("Original slice:", originalSlice) // [999 2 3]
fmt.Println("Modified slice:", modifiedSlice) // [999 2 3]
}
4.2 Map
package main
import "fmt"
func main() {
// 创建map
ages := make(map[string]int)
scores := map[string]int{
"Alice": 95,
"Bob": 87,
"Carol": 92,
}
// 添加/更新元素
ages["Alice"] = 25
ages["Bob"] = 30
ages["Alice"] = 26 // 更新
// 访问元素
aliceAge := ages["Alice"]
unknownAge := ages["Charlie"] // 返回零值(0)
// 检查键是否存在
if age, exists := ages["Alice"]; exists {
fmt.Printf("Alice is %d years old\n", age)
}
if _, exists := ages["Charlie"]; !exists {
fmt.Println("Charlie not found")
}
// 删除元素
delete(ages, "Bob")
// 遍历map
for name, age := range ages {
fmt.Printf("%s: %d\n", name, age)
}
// map长度
fmt.Printf("Number of people: %d\n", len(ages))
// map是引用类型
originalMap := map[string]int{"a": 1, "b": 2}
copiedMap := originalMap
copiedMap["a"] = 999
fmt.Println("Original map:", originalMap) // map[a:999 b:2]
fmt.Println("Copied map:", copiedMap) // map[a:999 b:2]
// 嵌套map
nested := map[string]map[string]int{
"math": {
"Alice": 95,
"Bob": 87,
},
"science": {
"Alice": 88,
"Carol": 92,
},
}
fmt.Println(nested["math"]["Alice"]) // 95
}
4.3 结构体
package main
import "fmt"
// 基本结构体
type Person struct {
Name string
Age int
City string
}
// 嵌套结构体
type Address struct {
Street string
City string
Zip string
}
type Employee struct {
Person // 匿名字段(嵌入)
ID int
Salary float64
Address // 嵌入Address
}
// 带标签的结构体(用于JSON等)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Active bool `json:"active"`
}
func main() {
// 创建结构体实例
person1 := Person{Name: "Alice", Age: 25, City: "New York"}
person2 := Person{"Bob", 30, "Los Angeles"} // 位置初始化(不推荐)
// 访问字段
fmt.Printf("%s is %d years old\n", person1.Name, person1.Age)
// 修改字段
person1.Age = 26
// 嵌套结构体
employee := Employee{
Person: Person{Name: "Carol", Age: 35, City: "Chicago"},
ID: 123,
Salary: 75000.50,
Address: Address{
Street: "123 Main St",
City: "Chicago",
Zip: "60601",
},
}
// 访问嵌入字段
fmt.Printf("Employee: %s (ID: %d)\n", employee.Name, employee.ID)
fmt.Printf("Address: %s, %s %s\n", employee.Street, employee.City, employee.Zip)
// 结构体指针
personPtr := &person1
personPtr.Age = 27 // 直接修改原结构体
// 结构体是值类型
original := Person{Name: "David", Age: 40}
copied := original
copied.Age = 41
fmt.Println("Original:", original) // {David 40 }
fmt.Println("Copied:", copied) // {David 41 }
}
第五章:函数和方法
5.1 函数基础
package main
import (
"errors"
"fmt"
)
// 基本函数
func add(a int, 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("division by zero")
}
return a / b, nil
}
// 命名返回值
func calculate(a, b int) (sum, difference int) {
sum = a + b
difference = a - b
return // naked return
}
// 可变参数
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
// 函数作为参数
func applyOperation(a, b int, operation func(int, int) int) int {
return operation(a, b)
}
// 函数作为返回值
func createMultiplier(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
func main() {
// 调用基本函数
result1 := add(5, 3)
result2 := multiply(4, 7)
fmt.Println(result1, result2) // 8 28
// 多返回值处理
quotient, err := divide(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Quotient:", quotient) // 5
}
// 命名返回值
s, d := calculate(10, 3)
fmt.Println("Sum:", s, "Difference:", d) // 13 7
// 可变参数
total := sum(1, 2, 3, 4, 5)
fmt.Println("Total:", total) // 15
// 函数作为参数
result3 := applyOperation(10, 5, add)
result4 := applyOperation(10, 5, multiply)
fmt.Println(result3, result4) // 15 50
// 函数作为返回值
double := createMultiplier(2)
triple := createMultiplier(3)
fmt.Println(double(5), triple(5)) // 10 15
// 匿名函数
greet := func(name string) string {
return "Hello, " + name + "!"
}
fmt.Println(greet("Alice")) // Hello, Alice!
// 立即调用函数表达式 (IIFE)
result5 := func(x, y int) int {
return x * x + y * y
}(3, 4)
fmt.Println(result5) // 25
}
5.2 方法
package main
import "fmt"
// 结构体定义
type Rectangle struct {
Width, Height float64
}
type Circle struct {
Radius 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) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
// Circle的方法
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Circumference() float64 {
return 2 * 3.14159 * c.Radius
}
// 接口实现
type Shape interface {
Area() float64
}
func printArea(s Shape) {
fmt.Printf("Area: %.2f\n", s.Area())
}
func main() {
// 创建实例
rect := Rectangle{Width: 5, Height: 3}
circle := Circle{Radius: 4}
// 调用方法
fmt.Printf("Rectangle area: %.2f\n", rect.Area())
fmt.Printf("Rectangle perimeter: %.2f\n", rect.Perimeter())
fmt.Printf("Circle area: %.2f\n", circle.Area())
fmt.Printf("Circle circumference: %.2f\n", circle.Circumference())
// 指针接收者方法
fmt.Printf("Before scaling: %+v\n", rect)
rect.Scale(2)
fmt.Printf("After scaling: %+v\n", rect)
// 接口使用
printArea(rect)
printArea(circle)
// 方法值和方法表达式
areaFunc := rect.Area
fmt.Printf("Area via method value: %.2f\n", areaFunc())
perimeterFunc := Rectangle.Perimeter
fmt.Printf("Perimeter via method expression: %.2f\n", perimeterFunc(rect))
}
5.3 错误处理
package main
import (
"errors"
"fmt"
"os"
)
// 自定义错误类型
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("validation error in field '%s': %s", e.Field, e.Message)
}
// 业务错误
type InsufficientFundsError struct {
Balance float64
Amount float64
}
func (e InsufficientFundsError) Error() string {
return fmt.Sprintf("insufficient funds: balance=%.2f, requested=%.2f", e.Balance, e.Amount)
}
// 函数返回错误
func validateEmail(email string) error {
if email == "" {
return ValidationError{Field: "email", Message: "cannot be empty"}
}
if !contains(email, "@") {
return ValidationError{Field: "email", Message: "must contain @"}
}
return nil
}
func withdraw(balance, amount float64) (float64, error) {
if amount <= 0 {
return balance, ValidationError{Field: "amount", Message: "must be positive"}
}
if amount > balance {
return balance, InsufficientFundsError{Balance: balance, Amount: amount}
}
return balance - amount, nil
}
// 错误包装(Go 1.13+)
func processFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open file %s: %w", filename, err)
}
defer file.Close()
// 处理文件...
return nil
}
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || contains(s[1:], substr))
}
func main() {
// 基本错误处理
email := "invalid-email"
if err := validateEmail(email); err != nil {
fmt.Println("Validation failed:", err)
}
// 业务错误处理
balance := 100.0
amount := 150.0
newBalance, err := withdraw(balance, amount)
if err != nil {
if insuffErr, ok := err.(InsufficientFundsError); ok {
fmt.Printf("Insufficient funds: balance=%.2f, amount=%.2f\n",
insuffErr.Balance, insuffErr.Amount)
} else {
fmt.Println("Other error:", err)
}
} else {
fmt.Printf("Withdrawal successful. New balance: %.2f\n", newBalance)
}
// 错误包装和解包
if err := processFile("nonexistent.txt"); err != nil {
fmt.Println("Process failed:", err)
// 检查特定错误类型
if os.IsNotExist(err) {
fmt.Println("File does not exist")
}
// 解包错误
var pathError *os.PathError
if errors.As(err, &pathError) {
fmt.Printf("Path error: %s (operation: %s)\n",
pathError.Path, pathError.Op)
}
}
// 错误比较
err1 := ValidationError{Field: "email", Message: "cannot be empty"}
err2 := ValidationError{Field: "email", Message: "cannot be empty"}
fmt.Println("Errors equal:", errors.Is(err1, err2)) // false (different instances)
// 使用errors.Is进行错误比较(Go 1.13+)
var ErrEmptyEmail = errors.New("email cannot be empty")
err3 := ErrEmptyEmail
fmt.Println("Standard error comparison:", errors.Is(err3, ErrEmptyEmail)) // true
}
第六章:接口和泛型
6.1 接口基础
package main
import "fmt"
// 基本接口
type Speaker interface {
Speak() string
}
type Animal interface {
Name() string
Sound() string
}
// 实现接口的结构体
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return "Woof!"
}
func (d Dog) Name() string {
return d.Name
}
func (d Dog) Sound() string {
return "Woof"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return "Meow!"
}
func (c Cat) Name() string {
return c.Name
}
func (c Cat) Sound() string {
return "Meow"
}
// 接口组合
type Pet interface {
Animal
Play() string
}
type Bird struct {
Name string
}
func (b Bird) Name() string {
return b.Name
}
func (b Bird) Sound() string {
return "Chirp"
}
func (b Bird) Play() string {
return "Flying around"
}
func (b Bird) Speak() string {
return "Tweet!"
}
// 空接口
func printAnything(v interface{}) {
fmt.Printf("Value: %v, Type: %T\n", v, v)
}
// 类型断言
func describeAnimal(a Animal) {
fmt.Printf("%s says %s\n", a.Name(), a.Sound())
// 类型断言
switch animal := a.(type) {
case Dog:
fmt.Println("It's a dog!")
case Cat:
fmt.Println("It's a cat!")
default:
fmt.Println("Unknown animal")
}
}
func main() {
// 使用接口
var speaker Speaker
speaker = Dog{Name: "Buddy"}
fmt.Println(speaker.Speak()) // Woof!
speaker = Cat{Name: "Whiskers"}
fmt.Println(speaker.Speak()) // Meow!
// 接口切片
animals := []Animal{
Dog{Name: "Rex"},
Cat{Name: "Fluffy"},
Bird{Name: "Tweety"},
}
for _, animal := range animals {
describeAnimal(animal)
}
// 接口组合
var pet Pet = Bird{Name: "Polly"}
fmt.Println(pet.Name(), pet.Sound(), pet.Play())
// 空接口
printAnything(42)
printAnything("hello")
printAnything(true)
printAnything([]int{1, 2, 3})
// 接口值和动态类型
var any interface{} = "hello"
fmt.Println(any) // hello
any = 42
fmt.Println(any) // 42
// 检查接口是否为nil
var speaker2 Speaker
if speaker2 == nil {
fmt.Println("speaker2 is nil")
}
}
6.2 泛型(Go 1.18+)
package main
import (
"fmt"
"golang.org/x/exp/constraints"
)
// 基本泛型函数
func min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}
func max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
// 泛型切片操作
func indexOf[T comparable](slice []T, target T) int {
for i, v := range slice {
if v == target {
return i
}
}
return -1
}
func contains[T comparable](slice []T, target T) bool {
return indexOf(slice, target) != -1
}
func filter[T any](slice []T, predicate func(T) bool) []T {
var result []T
for _, v := range slice {
if predicate(v) {
result = append(result, v)
}
}
return result
}
// 泛型结构体
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() (T, bool) {
var zero T
if len(s.items) == 0 {
return zero, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}
func (s *Stack[T]) Peek() (T, bool) {
var zero T
if len(s.items) == 0 {
return zero, false
}
return s.items[len(s.items)-1], true
}
func (s *Stack[T]) Size() int {
return len(s.items)
}
// 泛型接口
type Number interface {
constraints.Integer | constraints.Float
}
func sum[T Number](numbers []T) T {
var total T
for _, n := range numbers {
total += n
}
return total
}
// 泛型约束组合
type Stringer interface {
String() string
}
type Printable interface {
Stringer
comparable
}
// 泛型方法
type Container[T any] struct {
value T
}
func (c Container[T]) GetValue() T {
return c.value
}
func (c *Container[T]) SetValue(value T) {
c.value = value
}
func main() {
// 基本泛型函数
fmt.Println(min(5, 3)) // 3
fmt.Println(min(3.14, 2.71)) // 2.71
fmt.Println(max("apple", "banana")) // banana
// 泛型切片操作
numbers := []int{1, 2, 3, 4, 5}
fmt.Println(indexOf(numbers, 3)) // 2
fmt.Println(contains(numbers, 6)) // false
evens := filter(numbers, func(n int) bool {
return n%2 == 0
})
fmt.Println(evens) // [2 4]
// 泛型结构体
intStack := &Stack[int]{}
intStack.Push(1)
intStack.Push(2)
intStack.Push(3)
for intStack.Size() > 0 {
if item, ok := intStack.Pop(); ok {
fmt.Println("Popped:", item)
}
}
stringStack := &Stack[string]{}
stringStack.Push("hello")
stringStack.Push("world")
if top, ok := stringStack.Peek(); ok {
fmt.Println("Top:", top) // world
}
// 泛型接口
intSum := sum([]int{1, 2, 3, 4, 5})
floatSum := sum([]float64{1.1, 2.2, 3.3})
fmt.Println(intSum, floatSum) // 15 6.6
// 泛型容器
container := Container[string]{value: "initial"}
fmt.Println("Initial value:", container.GetValue())
container.SetValue("updated")
fmt.Println("Updated value:", container.GetValue())
}
6.3 接口最佳实践
package main
import (
"context"
"fmt"
"io"
"time"
)
// 小接口原则
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
// 接口组合
type ReadCloser interface {
Reader
Closer
}
type WriteCloser interface {
Writer
Closer
}
type ReadWriteCloser interface {
Reader
Writer
Closer
}
// 上下文接口
type Service interface {
Process(ctx context.Context, input string) (string, error)
}
// 模拟服务实现
type MockService struct{}
func (m MockService) Process(ctx context.Context, input string) (string, error) {
select {
case <-ctx.Done():
return "", ctx.Err()
case <-time.After(100 * time.Millisecond):
return "processed: " + input, nil
}
}
// 依赖注入
type Processor struct {
service Service
}
func NewProcessor(service Service) *Processor {
return &Processor{service: service}
}
func (p *Processor) Handle(input string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
return p.service.Process(ctx, input)
}
// 接口模拟(用于测试)
type MockReader struct {
Data []byte
Pos int
}
func (m *MockReader) Read(p []byte) (n int, err error) {
if m.Pos >= len(m.Data) {
return 0, io.EOF
}
n = copy(p, m.Data[m.Pos:])
m.Pos += n
return n, nil
}
func (m *MockReader) Close() error {
m.Pos = 0
return nil
}
// 接口适配器
type StringReader struct {
str string
pos int
}
func (s *StringReader) Read(p []byte) (n int, err error) {
if s.pos >= len(s.str) {
return 0, io.EOF
}
n = copy(p, s.str[s.pos:])
s.pos += n
return n, nil
}
func main() {
// 小接口使用
var reader Reader = &StringReader{str: "Hello, World!"}
buffer := make([]byte, 5)
n, err := reader.Read(buffer)
fmt.Printf("Read %d bytes: %s, error: %v\n", n, buffer[:n], err)
// 依赖注入
mockService := MockService{}
processor := NewProcessor(mockService)
result, err := processor.Handle("test input")
if err != nil {
fmt.Println("Error:", err) // context deadline exceeded
} else {
fmt.Println("Result:", result)
}
// 接口模拟
mockReader := &MockReader{Data: []byte("mock data")}
data := make([]byte, 10)
n, err = mockReader.Read(data)
fmt.Printf("Mock read %d bytes: %s, error: %v\n", n, data[:n], err)
// 接口组合
var rc ReadCloser = mockReader
rc.Close()
}
第七章:并发编程
7.1 Goroutine基础
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
// 启动goroutine
go say("world")
say("hello")
// 等待goroutine完成(简单方式)
time.Sleep(600 * time.Millisecond)
// 更好的同步方式
done := make(chan bool)
go func() {
fmt.Println("Goroutine starting")
time.Sleep(500 * time.Millisecond)
fmt.Println("Goroutine finished")
done <- true
}()
fmt.Println("Main waiting")
<-done
fmt.Println("Main finished")
}
7.2 Channel
package main
import (
"fmt"
"time"
)
func main() {
// 无缓冲channel
ch := make(chan int)
go func() {
fmt.Println("Sending 42")
ch <- 42
fmt.Println("Sent 42")
}()
fmt.Println("Receiving...")
value := <-ch
fmt.Printf("Received: %d\n", value)
// 带缓冲channel
bufferedCh := make(chan string, 2)
bufferedCh <- "first"
bufferedCh <- "second"
// bufferedCh <- "third" // 这会阻塞,因为缓冲区已满
fmt.Println(<-bufferedCh) // first
fmt.Println(<-bufferedCh) // second
// channel方向
sendOnly := make(chan<- int)
receiveOnly := make(<-chan int)
// 实际使用中通常在函数参数中指定方向
go sendData(sendOnly)
receiveData(receiveOnly)
// select语句
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
ch1 <- "from ch1"
}()
go func() {
time.Sleep(200 * time.Millisecond)
ch2 <- "from ch2"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("Received from ch1:", msg1)
case msg2 := <-ch2:
fmt.Println("Received from ch2:", msg2)
case <-time.After(300 * time.Millisecond):
fmt.Println("Timeout")
}
}
// 关闭channel
jobs := make(chan int, 5)
done := make(chan bool)
go func() {
for {
j, more := <-jobs
if more {
fmt.Println("Received job", j)
} else {
fmt.Println("No more jobs")
done <- true
return
}
}
}()
for j := 1; j <= 3; j++ {
jobs <- j
fmt.Println("Sent job", j)
}
close(jobs)
fmt.Println("Sent all jobs")
<-done
}
func sendData(ch chan<- int) {
ch <- 100
}
func receiveData(ch <-chan int) {
value := <-ch
fmt.Println("Received:", value)
}
7.3 同步原语
package main
import (
"fmt"
"sync"
"time"
)
func main() {
// WaitGroup
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Duration(id) * time.Second)
fmt.Printf("Worker %d finished\n", id)
}(i)
}
wg.Wait()
fmt.Println("All workers finished")
// Mutex
var counter int
var mutex sync.Mutex
var wg2 sync.WaitGroup
for i := 0; i < 1000; i++ {
wg2.Add(1)
go func() {
defer wg2.Done()
mutex.Lock()
counter++
mutex.Unlock()
}()
}
wg2.Wait()
fmt.Printf("Final counter: %d\n", counter)
// RWMutex
var data = make(map[string]int)
var rwMutex sync.RWMutex
// 读操作
go func() {
rwMutex.RLock()
value := data["key"]
rwMutex.RUnlock()
fmt.Printf("Read value: %d\n", value)
}()
// 写操作
rwMutex.Lock()
data["key"] = 42
rwMutex.Unlock()
// Once
var once sync.Once
var initialized bool
for i := 0; i < 5; i++ {
go func(id int) {
once.Do(func() {
fmt.Printf("Initializing (called by goroutine %d)\n", id)
initialized = true
})
fmt.Printf("Goroutine %d: initialized = %t\n", id, initialized)
}(i)
}
time.Sleep(100 * time.Millisecond)
// Pool
var pool = sync.Pool{
New: func() interface{} {
fmt.Println("Creating new object")
return &struct{ value int }{value: 0}
},
}
// 获取对象
obj1 := pool.Get().(*struct{ value int })
obj1.value = 42
fmt.Printf("Got object with value: %d\n", obj1.value)
// 归还对象
pool.Put(obj1)
// 再次获取(可能重用)
obj2 := pool.Get().(*struct{ value int })
fmt.Printf("Got object with value: %d\n", obj2.value)
}
7.4 高级并发模式
package main
import (
"context"
"fmt"
"sync"
"time"
)
// Worker Pool模式
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
time.Sleep(time.Second) // 模拟工作
results <- job * 2
}
}
// Fan-out/Fan-in模式
func fanOutFanIn() {
// 生成器
gen := func(nums ...int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for _, n := range nums {
out <- n
}
}()
return out
}
// 平方函数
sq := func(in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
out <- n * n
}
}()
return out
}
// 合并函数
merge := func(cs ...<-chan int) <-chan int {
var wg sync.WaitGroup
out := make(chan int)
output := func(c <-chan int) {
defer wg.Done()
for n := range c {
out <- n
}
}
wg.Add(len(cs))
for _, c := range cs {
go output(c)
}
go func() {
wg.Wait()
close(out)
}()
return out
}
// 使用
in := gen(2, 3, 4, 5)
c1 := sq(in)
c2 := sq(in)
for n := range merge(c1, c2) {
fmt.Println(n) // 4, 9, 16, 25 (顺序可能不同)
}
}
// Context取消模式
func doWork(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d cancelled: %v\n", id, ctx.Err())
return
default:
fmt.Printf("Worker %d working...\n", id)
time.Sleep(500 * time.Millisecond)
}
}
}
// 生产者-消费者模式
func producerConsumer() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// 生产者
go func() {
defer close(jobs)
for i := 1; i <= 10; i++ {
jobs <- i
fmt.Printf("Produced job %d\n", i)
}
}()
// 消费者
var wg sync.WaitGroup
for w := 1; w <= 3; w++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for job := range jobs {
result := job * job
fmt.Printf("Worker %d processed job %d, result: %d\n", id, job, result)
results <- result
}
}(w)
}
// 等待所有消费者完成
go func() {
wg.Wait()
close(results)
}()
// 收集结果
for result := range results {
fmt.Printf("Collected result: %d\n", result)
}
}
func main() {
// Worker Pool
fmt.Println("=== Worker Pool ===")
jobs := make(chan int, 100)
results := make(chan int, 100)
var wg sync.WaitGroup
for w := 1; w <= 3; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// 发送工作
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
wg.Wait()
close(results)
for result := range results {
fmt.Printf("Result: %d\n", result)
}
// Fan-out/Fan-in
fmt.Println("\n=== Fan-out/Fan-in ===")
fanOutFanIn()
// Context取消
fmt.Println("\n=== Context Cancellation ===")
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
go doWork(ctx, 1)
go doWork(ctx, 2)
time.Sleep(3 * time.Second)
// 生产者-消费者
fmt.Println("\n=== Producer-Consumer ===")
producerConsumer()
}
第八章:包管理和模块
8.1 Go Modules
# 初始化新模块
go mod init myproject
# 添加依赖
go get github.com/gin-gonic/gin@latest
go get github.com/sirupsen/logrus@v1.9.0
# 更新依赖
go get -u github.com/gin-gonic/gin
go get -u ./... # 更新所有依赖
# 清理未使用的依赖
go mod tidy
# 查看依赖图
go mod graph
# 验证依赖
go mod verify
# 下载依赖到本地缓存
go mod download
8.2 go.mod文件
// go.mod
module myproject
go 1.25
require (
github.com/gin-gonic/gin v1.10.0
github.com/sirupsen/logrus v1.9.3
golang.org/x/crypto v0.21.0
)
// 排除特定版本
exclude github.com/bad/package v1.0.0
// 替换依赖(用于本地开发或私有仓库)
replace github.com/my/private-lib => ../private-lib
replace github.com/old/package => github.com/new/package v2.0.0
// 间接依赖(通常由go mod tidy自动生成)
indirect
8.3 工作区模式(Go 1.18+)
# 创建工作区
go work init
go work use ./myproject
go work use ./shared-lib
# 工作区文件 (go.work)
go 1.25
use (
./myproject
./shared-lib
)
replace github.com/my/shared-lib => ./shared-lib
8.4 私有模块
# 配置私有模块
git config --global url."https://git.example.com".insteadOf "https://example.com"
# 或者设置GOPRIVATE环境变量
export GOPRIVATE=example.com/myorg/*
# 在go.mod中使用
require example.com/myorg/mymodule v1.0.0
第九章:测试和基准测试
9.1 单元测试
// math.go
package main
func Add(a, b int) int {
return a + b
}
func Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
// math_test.go
package main
import (
"testing"
)
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -2, -3, -5},
{"mixed numbers", 2, -3, -1},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
}
})
}
}
func TestDivide(t *testing.T) {
tests := []struct {
name string
a, b float64
expected float64
expectError bool
}{
{"normal division", 10, 2, 5, false},
{"division by zero", 10, 0, 0, true},
{"negative numbers", -10, 2, -5, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := Divide(tt.a, tt.b)
if tt.expectError {
if err == nil {
t.Error("Expected error but got none")
}
} else {
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if result != tt.expected {
t.Errorf("Divide(%f, %f) = %f; expected %f", tt.a, tt.b, result, tt.expected)
}
}
})
}
}
func TestMain(m *testing.M) {
// 测试前设置
setup()
// 运行测试
code := m.Run()
// 测试后清理
cleanup()
os.Exit(code)
}
9.2 基准测试
// benchmark_test.go
package main
import (
"strconv"
"testing"
)
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}
func BenchmarkStringConcat(b *testing.B) {
s1, s2 := "hello", "world"
b.Run("plus", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = s1 + " " + s2
}
})
b.Run("sprintf", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%s %s", s1, s2)
}
})
b.Run("builder", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var builder strings.Builder
builder.WriteString(s1)
builder.WriteString(" ")
builder.WriteString(s2)
_ = builder.String()
}
})
}
func BenchmarkParsing(b *testing.B) {
input := "12345"
b.Run("strconv", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = strconv.Atoi(input)
}
})
b.Run("fmt", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var n int
_, _ = fmt.Sscanf(input, "%d", &n)
}
})
}
// 内存分配基准测试
func BenchmarkMemoryAllocation(b *testing.B) {
b.Run("slice", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = make([]int, 1000)
}
})
b.Run("map", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = make(map[string]int, 1000)
}
})
}
9.3 模拟和测试工具
// repository.go
package main
import (
"context"
"database/sql"
)
type User struct {
ID int
Name string
Email string
}
type UserRepository interface {
GetUserByID(ctx context.Context, id int) (*User, error)
CreateUser(ctx context.Context, user *User) error
}
type SQLUserRepository struct {
db *sql.DB
}
func (r *SQLUserRepository) GetUserByID(ctx context.Context, id int) (*User, error) {
// 数据库查询实现
return &User{ID: id, Name: "John", Email: "john@example.com"}, nil
}
func (r *SQLUserRepository) CreateUser(ctx context.Context, user *User) error {
// 数据库插入实现
return nil
}
// service.go
type UserService struct {
repo UserRepository
}
func NewUserService(repo UserRepository) *UserService {
return &UserService{repo: repo}
}
func (s *UserService) GetUserProfile(ctx context.Context, userID int) (*User, error) {
return s.repo.GetUserByID(ctx, userID)
}
// service_test.go
package main
import (
"context"
"testing"
)
// Mock实现
type MockUserRepository struct {
getUserByIDFunc func(ctx context.Context, id int) (*User, error)
createUserFunc func(ctx context.Context, user *User) error
}
func (m *MockUserRepository) GetUserByID(ctx context.Context, id int) (*User, error) {
if m.getUserByIDFunc != nil {
return m.getUserByIDFunc(ctx, id)
}
return nil, nil
}
func (m *MockUserRepository) CreateUser(ctx context.Context, user *User) error {
if m.createUserFunc != nil {
return m.createUserFunc(ctx, user)
}
return nil
}
func TestUserService_GetUserProfile(t *testing.T) {
expectedUser := &User{ID: 1, Name: "Alice", Email: "alice@example.com"}
mockRepo := &MockUserRepository{
getUserByIDFunc: func(ctx context.Context, id int) (*User, error) {
if id == 1 {
return expectedUser, nil
}
return nil, fmt.Errorf("user not found")
},
}
service := NewUserService(mockRepo)
user, err := service.GetUserProfile(context.Background(), 1)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if user.ID != expectedUser.ID || user.Name != expectedUser.Name {
t.Errorf("Expected user %+v, got %+v", expectedUser, user)
}
// 测试错误情况
_, err = service.GetUserProfile(context.Background(), 999)
if err == nil {
t.Error("Expected error for non-existent user")
}
}
// 使用testify/mock(第三方库)
// go get github.com/stretchr/testify/mock
import (
"github.com/stretchr/testify/mock"
)
type MockUserRepository2 struct {
mock.Mock
}
func (m *MockUserRepository2) GetUserByID(ctx context.Context, id int) (*User, error) {
args := m.Called(ctx, id)
return args.Get(0).(*User), args.Error(1)
}
func (m *MockUserRepository2) CreateUser(ctx context.Context, user *User) error {
args := m.Called(ctx, user)
return args.Error(0)
}
func TestUserServiceWithTestify(t *testing.T) {
mockRepo := new(MockUserRepository2)
expectedUser := &User{ID: 1, Name: "Bob", Email: "bob@example.com"}
mockRepo.On("GetUserByID", mock.Anything, 1).Return(expectedUser, nil)
service := NewUserService(mockRepo)
user, err := service.GetUserProfile(context.Background(), 1)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if user.Name != "Bob" {
t.Errorf("Expected Bob, got %s", user.Name)
}
mockRepo.AssertExpectations(t)
}
9.4 代码覆盖率
# 运行测试并生成覆盖率报告
go test -coverprofile=coverage.out ./...
# 在浏览器中查看覆盖率
go tool cover -html=coverage.out
# 显示覆盖率百分比
go test -cover ./...
# 按函数显示覆盖率
go tool cover -func=coverage.out
第十章:Web开发
10.1 标准库HTTP服务器
// server.go
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"time"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
var users = []User{
{ID: 1, Name: "Alice", Email: "alice@example.com"},
{ID: 2, Name: "Bob", Email: "bob@example.com"},
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
func getUsersHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func getUserHandler(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
if idStr == "" {
http.Error(w, "Missing id parameter", http.StatusBadRequest)
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "Invalid id parameter", http.StatusBadRequest)
return
}
for _, user := range users {
if user.ID == id {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
return
}
}
http.Error(w, "User not found", http.StatusNotFound)
}
func createUserHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var newUser User
if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// 简单的ID生成
newUser.ID = len(users) + 1
users = append(users, newUser)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(newUser)
}
func middleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("Started %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("Completed %s %s in %v", r.Method, r.URL.Path, time.Since(start))
}
}
func main() {
http.HandleFunc("/health", middleware(healthHandler))
http.HandleFunc("/users", middleware(getUsersHandler))
http.HandleFunc("/user", middleware(getUserHandler))
http.HandleFunc("/user/create", middleware(createUserHandler))
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
10.2 Gin框架
// gin_server.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type CreateUserRequest struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required,email"`
}
type UserResponse struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
var users = []UserResponse{
{ID: 1, Name: "Alice", Email: "alice@example.com"},
{ID: 2, Name: "Bob", Email: "bob@example.com"},
}
func main() {
r := gin.Default()
// 健康检查
r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
// 获取所有用户
r.GET("/users", func(c *gin.Context) {
c.JSON(http.StatusOK, users)
})
// 获取单个用户
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
for _, user := range users {
if fmt.Sprintf("%d", user.ID) == id {
c.JSON(http.StatusOK, user)
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
})
// 创建用户
r.POST("/users", func(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
newUser := UserResponse{
ID: len(users) + 1,
Name: req.Name,
Email: req.Email,
}
users = append(users, newUser)
c.JSON(http.StatusCreated, newUser)
})
// 更新用户
r.PUT("/users/:id", func(c *gin.Context) {
id := c.Param("id")
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
for i, user := range users {
if fmt.Sprintf("%d", user.ID) == id {
users[i].Name = req.Name
users[i].Email = req.Email
c.JSON(http.StatusOK, users[i])
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
})
// 删除用户
r.DELETE("/users/:id", func(c *gin.Context) {
id := c.Param("id")
for i, user := range users {
if fmt.Sprintf("%d", user.ID) == id {
users = append(users[:i], users[i+1:]...)
c.JSON(http.StatusNoContent, nil)
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
})
r.Run(":8080")
}
10.3 数据库操作
// database.go
package main
import (
"context"
"database/sql"
"fmt"
"log"
"time"
_ "github.com/lib/pq" // PostgreSQL driver
// _ "github.com/go-sql-driver/mysql" // MySQL driver
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
type UserRepository struct {
db *sql.DB
}
func NewUserRepository(db *sql.DB) *UserRepository {
return &UserRepository{db: db}
}
func (r *UserRepository) Create(ctx context.Context, user *User) error {
query := `INSERT INTO users (name, email, created_at) VALUES ($1, $2, $3) RETURNING id`
return r.db.QueryRowContext(ctx, query, user.Name, user.Email, time.Now()).Scan(&user.ID)
}
func (r *UserRepository) GetByID(ctx context.Context, id int) (*User, error) {
query := `SELECT id, name, email, created_at FROM users WHERE id = $1`
row := r.db.QueryRowContext(ctx, query, id)
var user User
err := row.Scan(&user.ID, &user.Name, &user.Email, &user.CreatedAt)
if err != nil {
if err == sql.ErrNoRows {
return nil, fmt.Errorf("user not found")
}
return nil, err
}
return &user, nil
}
func (r *UserRepository) GetAll(ctx context.Context) ([]*User, error) {
query := `SELECT id, name, email, created_at FROM users ORDER BY id`
rows, err := r.db.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer rows.Close()
var users []*User
for rows.Next() {
var user User
if err := rows.Scan(&user.ID, &user.Name, &user.Email, &user.CreatedAt); err != nil {
return nil, err
}
users = append(users, &user)
}
return users, rows.Err()
}
func (r *UserRepository) Update(ctx context.Context, user *User) error {
query := `UPDATE users SET name = $1, email = $2 WHERE id = $3`
result, err := r.db.ExecContext(ctx, query, user.Name, user.Email, user.ID)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return fmt.Errorf("user not found")
}
return nil
}
func (r *UserRepository) Delete(ctx context.Context, id int) error {
query := `DELETE FROM users WHERE id = $1`
result, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return fmt.Errorf("user not found")
}
return nil
}
func main() {
// 连接数据库
db, err := sql.Open("postgres", "host=localhost port=5432 user=postgres password=secret dbname=myapp sslmode=disable")
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
defer db.Close()
// 测试连接
if err := db.Ping(); err != nil {
log.Fatal("Failed to ping database:", err)
}
// 设置连接池
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
repo := NewUserRepository(db)
ctx := context.Background()
// 创建用户
user := &User{Name: "Charlie", Email: "charlie@example.com"}
if err := repo.Create(ctx, user); err != nil {
log.Fatal("Failed to create user:", err)
}
fmt.Printf("Created user: %+v\n", user)
// 获取用户
retrievedUser, err := repo.GetByID(ctx, user.ID)
if err != nil {
log.Fatal("Failed to get user:", err)
}
fmt.Printf("Retrieved user: %+v\n", retrievedUser)
// 更新用户
retrievedUser.Name = "Charles"
if err := repo.Update(ctx, retrievedUser); err != nil {
log.Fatal("Failed to update user:", err)
}
fmt.Println("Updated user")
// 获取所有用户
allUsers, err := repo.GetAll(ctx)
if err != nil {
log.Fatal("Failed to get all users:", err)
}
fmt.Printf("All users: %+v\n", allUsers)
// 删除用户
if err := repo.Delete(ctx, user.ID); err != nil {
log.Fatal("Failed to delete user:", err)
}
fmt.Println("Deleted user")
}
10.4 REST API最佳实践
// api.go
package main
import (
"context"
"encoding/json"
"errors"
"log"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
// 全局错误类型
var (
ErrNotFound = errors.New("resource not found")
ErrInvalidInput = errors.New("invalid input")
ErrInternal = errors.New("internal server error")
ErrUnauthorized = errors.New("unauthorized")
)
// 错误响应结构
type ErrorResponse struct {
Error string `json:"error"`
Message string `json:"message"`
}
// 成功响应结构
type SuccessResponse struct {
Data interface{} `json:"data,omitempty"`
Meta interface{} `json:"meta,omitempty"`
}
// 分页元数据
type PaginationMeta struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int `json:"total"`
TotalPages int `json:"total_pages"`
}
// 用户模型
type User struct {
ID int `json:"id" gorm:"primaryKey"`
Name string `json:"name" validate:"required,min=2,max=50"`
Email string `json:"email" validate:"required,email"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// 请求模型
type CreateUserRequest struct {
Name string `json:"name" validate:"required,min=2,max=50"`
Email string `json:"email" validate:"required,email"`
}
type UpdateUserRequest struct {
Name string `json:"name" validate:"required,min=2,max=50"`
Email string `json:"email" validate:"required,email"`
}
// 服务层
type UserService interface {
Create(ctx context.Context, req *CreateUserRequest) (*User, error)
GetByID(ctx context.Context, id int) (*User, error)
GetAll(ctx context.Context, page, pageSize int) ([]*User, *PaginationMeta, error)
Update(ctx context.Context, id int, req *UpdateUserRequest) (*User, error)
Delete(ctx context.Context, id int) error
}
// 服务实现
type userService struct {
// userRepository UserRepository
}
func (s *userService) Create(ctx context.Context, req *CreateUserRequest) (*User, error) {
// 验证输入
if err := validate.Struct(req); err != nil {
return nil, ErrInvalidInput
}
// 创建用户逻辑
user := &User{
Name: req.Name,
Email: req.Email,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// 保存到数据库
// s.userRepository.Create(ctx, user)
return user, nil
}
func (s *userService) GetByID(ctx context.Context, id int) (*User, error) {
if id <= 0 {
return nil, ErrInvalidInput
}
// 从数据库获取
// user, err := s.userRepository.GetByID(ctx, id)
// if err != nil {
// if errors.Is(err, ErrNotFound) {
// return nil, ErrNotFound
// }
// return nil, ErrInternal
// }
// 模拟数据
return &User{ID: id, Name: "Test User", Email: "test@example.com"}, nil
}
func (s *userService) GetAll(ctx context.Context, page, pageSize int) ([]*User, *PaginationMeta, error) {
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 10
}
// 从数据库获取分页数据
// users, total, err := s.userRepository.GetAll(ctx, page, pageSize)
// if err != nil {
// return nil, nil, ErrInternal
// }
// 模拟数据
users := []*User{
{ID: 1, Name: "Alice", Email: "alice@example.com"},
{ID: 2, Name: "Bob", Email: "bob@example.com"},
}
total := 2
meta := &PaginationMeta{
Page: page,
PageSize: pageSize,
Total: total,
TotalPages: (total + pageSize - 1) / pageSize,
}
return users, meta, nil
}
func (s *userService) Update(ctx context.Context, id int, req *UpdateUserRequest) (*User, error) {
if id <= 0 {
return nil, ErrInvalidInput
}
if err := validate.Struct(req); err != nil {
return nil, ErrInvalidInput
}
// 更新用户逻辑
// user, err := s.userRepository.GetByID(ctx, id)
// if err != nil {
// if errors.Is(err, ErrNotFound) {
// return nil, ErrNotFound
// }
// return nil, ErrInternal
// }
//
// user.Name = req.Name
// user.Email = req.Email
// user.UpdatedAt = time.Now()
// s.userRepository.Update(ctx, user)
return &User{ID: id, Name: req.Name, Email: req.Email}, nil
}
func (s *userService) Delete(ctx context.Context, id int) error {
if id <= 0 {
return ErrInvalidInput
}
// 删除用户逻辑
// if err := s.userRepository.Delete(ctx, id); err != nil {
// if errors.Is(err, ErrNotFound) {
// return ErrNotFound
// }
// return ErrInternal
// }
return nil
}
// 验证器
var validate *validator.Validate
func init() {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
validate = v
}
}
// 中间件
func errorMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
if len(c.Errors) > 0 {
err := c.Errors.Last().Err
var statusCode int
var message string
switch {
case errors.Is(err, ErrNotFound):
statusCode = http.StatusNotFound
message = "Resource not found"
case errors.Is(err, ErrInvalidInput):
statusCode = http.StatusBadRequest
message = "Invalid input"
case errors.Is(err, ErrUnauthorized):
statusCode = http.StatusUnauthorized
message = "Unauthorized"
default:
statusCode = http.StatusInternalServerError
message = "Internal server error"
log.Printf("Internal error: %v", err)
}
c.JSON(statusCode, ErrorResponse{
Error: err.Error(),
Message: message,
})
}
}
}
func paginationMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
pageStr := c.DefaultQuery("page", "1")
pageSizeStr := c.DefaultQuery("page_size", "10")
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 || pageSize > 100 {
pageSize = 10
}
c.Set("page", page)
c.Set("page_size", pageSize)
c.Next()
}
}
// 控制器
type UserController struct {
service UserService
}
func NewUserController(service UserService) *UserController {
return &UserController{service: service}
}
func (uc *UserController) CreateUser(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(ErrInvalidInput)
return
}
user, err := uc.service.Create(c.Request.Context(), &req)
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusCreated, SuccessResponse{Data: user})
}
func (uc *UserController) GetUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.Error(ErrInvalidInput)
return
}
user, err := uc.service.GetByID(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusOK, SuccessResponse{Data: user})
}
func (uc *UserController) GetUsers(c *gin.Context) {
page, _ := c.Get("page")
pageSize, _ := c.Get("page_size")
users, meta, err := uc.service.GetAll(c.Request.Context(), page.(int), pageSize.(int))
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusOK, SuccessResponse{Data: users, Meta: meta})
}
func (uc *UserController) UpdateUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.Error(ErrInvalidInput)
return
}
var req UpdateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(ErrInvalidInput)
return
}
user, err := uc.service.Update(c.Request.Context(), id, &req)
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusOK, SuccessResponse{Data: user})
}
func (uc *UserController) DeleteUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.Error(ErrInvalidInput)
return
}
err = uc.service.Delete(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusNoContent, nil)
}
func main() {
r := gin.Default()
// 注册中间件
r.Use(errorMiddleware())
r.Use(gin.Logger())
r.Use(gin.Recovery())
// 创建服务和控制器
service := &userService{}
userController := NewUserController(service)
// 路由
api := r.Group("/api/v1")
{
api.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok", "version": "1.0.0"})
})
users := api.Group("/users")
users.Use(paginationMiddleware())
{
users.POST("", userController.CreateUser)
users.GET("", userController.GetUsers)
users.GET("/:id", userController.GetUser)
users.PUT("/:id", userController.UpdateUser)
users.DELETE("/: id", userController.DeleteUser)
}
}
r.Run(":8080")
}
第十一章:实际应用场景
11.1 CLI工具开发
// cli.go
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var (
cfgFile string
verbose bool
)
func main() {
rootCmd := &cobra.Command{
Use: "mycli",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application.`,
Run: func(cmd *cobra.Command, args []string) {
if verbose {
fmt.Println("Verbose mode enabled")
}
fmt.Println("Welcome to mycli!")
},
}
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.mycli.yaml)")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
// 子命令
var name string
greetCmd := &cobra.Command{
Use: "greet",
Short: "Greet someone",
Long: `Greet someone by name`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
name = args[0]
if verbose {
fmt.Printf("Greeting %s\n", name)
}
fmt.Printf("Hello, %s!\n", name)
},
}
rootCmd.AddCommand(greetCmd)
// 文件操作子命令
fileCmd := &cobra.Command{
Use: "file",
Short: "File operations",
Long: `Operations on files`,
}
createCmd := &cobra.Command{
Use: "create [filename]",
Short: "Create a file",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
filename := args[0]
if err := os.WriteFile(filename, []byte("Hello, World!"), 0644); err != nil {
fmt.Printf("Error creating file: %v\n", err)
os.Exit(1)
}
fmt.Printf("Created file: %s\n", filename)
},
}
fileCmd.AddCommand(createCmd)
rootCmd.AddCommand(fileCmd)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
11.2 微服务架构
// microservice.go
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"time"
"github.com/redis/go-redis/v9"
"github.com/streadway/amqp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
// 消息结构
type OrderCreatedEvent struct {
OrderID string `json:"order_id"`
CustomerID string `json:"customer_id"`
Amount float64 `json:"amount"`
CreatedAt time.Time `json:"created_at"`
}
type InventoryService struct {
redisClient *redis.Client
amqpChannel *amqp.Channel
tracer trace.Tracer
}
func NewInventoryService(redisAddr, amqpURL string) (*InventoryService, error) {
// Redis连接
redisClient := redis.NewClient(&redis.Options{
Addr: redisAddr,
DB: 0,
})
// AMQP连接
conn, err := amqp.Dial(amqpURL)
if err != nil {
return nil, err
}
channel, err := conn.Channel()
if err != nil {
return nil, err
}
// OpenTelemetry配置
exporter, err := jaeger.New(jaeger.WithCollectorEndpoint())
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("inventory-service"),
)),
)
otel.SetTracerProvider(tp)
tracer := otel.Tracer("inventory-service")
return &InventoryService{
redisClient: redisClient,
amqpChannel: channel,
tracer: tracer,
}, nil
}
func (s *InventoryService) ReserveStock(ctx context.Context, productID string, quantity int) error {
ctx, span := s.tracer.Start(ctx, "ReserveStock")
defer span.End()
key := "stock:" + productID
current, err := s.redisClient.Get(ctx, key).Int()
if err != nil && err != redis.Nil {
return err
}
if current < quantity {
return fmt.Errorf("insufficient stock for product %s", productID)
}
_, err = s.redisClient.DecrBy(ctx, key, int64(quantity)).Result()
return err
}
func (s *InventoryService) ProcessOrderCreated(ctx context.Context, event *OrderCreatedEvent) error {
ctx, span := s.tracer.Start(ctx, "ProcessOrderCreated")
defer span.End()
// 解析订单项(简化)
productID := "product-123" // 从事件中获取
quantity := 1 // 从事件中获取
if err := s.ReserveStock(ctx, productID, quantity); err != nil {
// 发布库存不足事件
insufficientEvent := map[string]interface{}{
"order_id": event.OrderID,
"reason": err.Error(),
}
body, _ := json.Marshal(insufficientEvent)
s.amqpChannel.Publish(
"",
"inventory.insufficient",
false,
false,
amqp.Publishing{
ContentType: "application/json",
Body: body,
},
)
return err
}
// 发布库存预留成功事件
reservedEvent := map[string]interface{}{
"order_id": event.OrderID,
"product_id": productID,
"quantity": quantity,
}
body, _ := json.Marshal(reservedEvent)
s.amqpChannel.Publish(
"",
"inventory.reserved",
false,
false,
amqp.Publishing{
ContentType: "application/json",
Body: body,
},
)
return nil
}
func (s *InventoryService) StartMessageConsumer(ctx context.Context) error {
q, err := s.amqpChannel.QueueDeclare(
"order.created",
true,
false,
false,
false,
nil,
)
if err != nil {
return err
}
s.amqpChannel.QueueBind(
q.Name,
"order.created",
"events",
false,
nil,
)
msgs, err := s.amqpChannel.Consume(
q.Name,
"",
true,
false,
false,
false,
nil,
)
if err != != nil {
return err
}
go func() {
for msg := range msgs {
var event OrderCreatedEvent
if err := json.Unmarshal(msg.Body, &event); err != nil {
log.Printf("Failed to unmarshal message: %v", err)
continue
}
if err := s.ProcessOrderCreated(ctx, &event); err != nil {
log.Printf("Failed to process order created event: %v", err)
}
}
}()
return nil
}
func (s *InventoryService) HealthCheck(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
func main() {
ctx := context.Background()
service, err := NewInventoryService("localhost:6379", "amqp://guest:guest@localhost:5672/")
if err != nil {
log.Fatal("Failed to create inventory service:", err)
}
// 启动消息消费者
if err := service.StartMessageConsumer(ctx); err != nil {
log.Fatal("Failed to start message consumer:", err)
}
// HTTP服务器
http.HandleFunc("/health", service.HealthCheck)
log.Println("Inventory service starting on :8081")
log.Fatal(http.ListenAndServe(":8081", nil))
}
11.3 数据处理管道
// pipeline.go
package main
import (
"bufio"
"context"
"encoding/csv"
"fmt"
"os"
"strconv"
"sync"
"time"
)
// 数据模型
type Record struct {
ID int
Name string
Value float64
}
// 管道阶段
func readFile(ctx context.Context, filename string) (<-chan string, <-chan error) {
out := make(chan string)
errs := make(chan error, 1)
go func() {
defer close(out)
defer close(errs)
file, err := os.Open(filename)
if err != nil {
errs <- err
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
select {
case out <- scanner.Text():
case <-ctx.Done():
return
}
}
if err := scanner.Err(); err != nil {
errs <- err
}
}()
return out, errs
}
func parseCSV(ctx context.Context, lines <-chan string) (<-chan []string, <-chan error) {
out := make(chan []string)
errs := make(chan error, 1)
go func() {
defer close(out)
defer close(errs)
reader := csv.NewReader(nil)
for line := range lines {
reader.Reset(strings.NewReader(line))
record, err := reader.Read()
if err != nil {
errs <- err
return
}
select {
case out <- record:
case <-ctx.Done():
return
}
}
}()
return out, errs
}
func transformRecords(ctx context.Context, records <-chan []string) (<-chan Record, <-chan error) {
out := make(chan Record)
errs := make(chan error, 1)
go func() {
defer close(out)
defer close(errs)
for record := range records {
if len(record) < 3 {
errs <- fmt.Errorf("invalid record: %v", record)
return
}
id, err := strconv.Atoi(record[0])
if err != nil {
errs <- fmt.Errorf("invalid ID: %s", record[0])
return
}
value, err := strconv.ParseFloat(record[2], 64)
if err != nil {
errs <- fmt.Errorf("invalid value: %s", record[2])
return
}
transformed := Record{
ID: id,
Name: record[1],
Value: value,
}
select {
case out <- transformed:
case <-ctx.Done():
return
}
}
}()
return out, errs
}
func processRecords(ctx context.Context, records <-chan Record, batchSize int) (<-chan []Record, <-chan error) {
out := make(chan []Record)
errs := make(chan error, 1)
go func() {
defer close(out)
defer close(errs)
var batch []Record
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case record, ok := <-records:
if !ok {
// 输入通道关闭,发送剩余批次
if len(batch) > 0 {
out <- batch
}
return
}
batch = append(batch, record)
if len(batch) >= batchSize {
out <- batch
batch = nil
}
case <-ticker.C:
// 定时发送批次
if len(batch) > 0 {
out <- batch
batch = nil
}
case <-ctx.Done():
return
}
}
}()
return out, errs
}
func saveToDatabase(ctx context.Context, batches <-chan []Record) <-chan error {
errs := make(chan error, 1)
go func() {
defer close(errs)
for batch := range batches {
// 模拟数据库保存
time.Sleep(100 * time.Millisecond)
fmt.Printf("Saved batch of %d records\n", len(batch))
}
}()
return errs
}
func runPipeline(ctx context.Context, filename string) error {
lines, lineErrs := readFile(ctx, filename)
records, recordErrs := parseCSV(ctx, lines)
transformed, transformErrs := transformRecords(ctx, records)
batches, batchErrs := processRecords(ctx, transformed, 10)
saveErrs := saveToDatabase(ctx, batches)
// 错误处理
var wg sync.WaitGroup
errChan := make(chan error, 5)
collectErrors := func(errs <-chan error) {
defer wg.Done()
for err := range errs {
errChan <- err
}
}
wg.Add(5)
go collectErrors(lineErrs)
go collectErrors(recordErrs)
go collectErrors(transformErrs)
go collectErrors(batchErrs)
go collectErrors(saveErrs)
// 等待完成或错误
go func() {
wg.Wait()
close(errChan)
}()
select {
case err := <-errChan:
if err != nil {
return err
}
case <-ctx.Done():
return ctx.Err()
}
return nil
}
func main() {
// 创建示例CSV文件
sampleData := `1,Alice,100.5
2,Bob,200.75
3,Carol,150.25
4,David,300.0
5,Eve,175.8`
os.WriteFile("sample.csv", []byte(sampleData), 0644)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := runPipeline(ctx, "sample.csv"); err != nil {
fmt.Printf("Pipeline failed: %v\n", err)
} else {
fmt.Println("Pipeline completed successfully")
}
}
总结
Go语言作为一门现代化的系统编程语言,在2026年继续保持着其在云原生、微服务和高性能应用领域的领先地位。通过本文的学习,你应该已经掌握了:
- 基础语法:变量、数据类型、控制结构、函数
- 复合类型:数组、切片、map、结构体
- 面向对象:方法、接口、组合优于继承
- 泛型编程:类型参数、约束、泛型数据结构
- 并发模型:goroutine、channel、同步原语、并发模式
- 错误处理:多返回值、错误包装、自定义错误
- 包管理:Go modules、依赖管理、工作区
- 测试:单元测试、基准测试、模拟、覆盖率
- Web开发:HTTP服务器、REST API、数据库操作
- 实际应用:CLI工具、微服务、数据处理管道
学习建议:
- 从简单的命令行程序开始,逐步构建Web服务
- 阅读优秀的Go代码,如标准库和知名开源项目
- 遵循Go的惯用法和最佳实践
- 关注Go社区的最新动态和发展趋势
- 在实际项目中不断练习和应用所学知识
Go的学习是一个持续的过程,随着你对语言特性和最佳实践的深入理解,你会发现更多高级功能和应用场景。希望这篇指南能够为你打下坚实的基础,助你在Go开发的道路上越走越远!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)