1. 为什么选择 Go 做服务器开发?

🚀 性能优势

  • 编译为原生机器码,接近 C 性能
  • 内置高效 GC,停顿时间 <1ms
  • goroutine 栈初始 2KB,可承载百万并发
  • 内置 CPU profiler,易于调优

⚡ 开发效率

  • 编译速度极快(秒级)
  • 语法简洁,学习曲线平缓
  • 强大的标准库,net/http 开箱即用
  • 静态类型 + 类型推断,安全不冗余

2. 快速安装与工程结构

安装 Go

# macOS
brew install go

# 验证安装
go version  # go version go1.22.x darwin/arm64

# 设置模块代理 (国内加速)
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GONOSUMCHECK=*

标准工程结构

myservice/
├── cmd/
│   └── server/
│       └── main.go          # 程序入口
├── internal/                # 私有包 (外部无法 import)
│   ├── handler/             # HTTP 处理器
│   ├── service/             # 业务逻辑层
│   ├── repository/          # 数据访问层
│   └── model/               # 数据模型
├── pkg/                     # 可复用的公共包
│   ├── logger/
│   └── config/
├── api/                     # OpenAPI/Protobuf 定义
├── config/                  # 配置文件
├── migrations/              # 数据库迁移
├── go.mod                   # 模块依赖
├── go.sum                   # 依赖校验
└── Makefile                 # 构建脚本
# 初始化模块
mkdir myservice && cd myservice
go mod init github.com/yourname/myservice

# 添加依赖
go get github.com/gin-gonic/gin
go get gorm.io/gorm

# 整理依赖
go mod tidy

3. Go 类型系统

package main

import "fmt"

// 基础类型
var (
    name    string  = "Alice"
    age     int     = 30
    score   float64 = 98.5
    active  bool    = true
    data    []byte  = []byte{0x48, 0x65}
)

// 类型推断
host := "localhost"
port := 8080

// 结构体 (核心数据组织方式)
type User struct {
    ID        int64     `json:"id" db:"id"`
    Name      string    `json:"name" db:"name"`
    Email     string    `json:"email" db:"email"`
    Password  string    `json:"-"`              // json 序列化时忽略
    CreatedAt time.Time `json:"created_at"`
}

// 方法 (值接收者 vs 指针接收者)
func (u User) String() string {
    return fmt.Sprintf("User{%d, %s}", u.ID, u.Name)
}

func (u *User) SetEmail(email string) {
    u.Email = email  // 修改原始数据需要指针接收者
}

// 接口
type Stringer interface {
    String() string
}

// 枚举模拟
type Status int

const (
    StatusPending Status = iota  // 0
    StatusActive                 // 1
    StatusDisabled               // 2
)

func (s Status) String() string {
    return [...]string{"pending", "active", "disabled"}[s]
}

// map 与 slice
func main() {
    // slice
    users := []User{
        {ID: 1, Name: "Alice"},
        {ID: 2, Name: "Bob"},
    }
    users = append(users, User{ID: 3, Name: "Charlie"})

    // map
    cache := map[string]int{
        "hits":   100,
        "misses": 5,
    }
    // 安全访问 (comma-ok 惯用法)
    val, ok := cache["hits"]
    if ok {
        fmt.Println("命中次数:", val)
    }

    // range 遍历
    for i, u := range users {
        fmt.Printf("[%d] %s\n", i, u.Name)
    }
}

4. 错误处理

ℹ️

Go 的错误哲学

Go 将错误视为普通值,而非异常。函数通过多返回值返回错误,调用者必须显式处理——这使错误处理可见且可靠。

package main

import (
    "errors"
    "fmt"
)

// 自定义错误类型
type AppError struct {
    Code    int
    Message string
    Err     error // 原始错误 (错误链)
}

func (e *AppError) Error() string {
    if e.Err != nil {
        return fmt.Sprintf("[%d] %s: %v", e.Code, e.Message, e.Err)
    }
    return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}

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

// 哨兵错误
var (
    ErrNotFound   = errors.New("resource not found")
    ErrUnauthorized = errors.New("unauthorized")
    ErrValidation = errors.New("validation failed")
)

func findUser(id int) (*User, error) {
    if id <= 0 {
        return nil, &AppError{Code: 400, Message: "invalid id", Err: ErrValidation}
    }
    if id > 100 {
        return nil, fmt.Errorf("findUser: %w", ErrNotFound) // %w 包装错误
    }
    return &User{ID: int64(id), Name: "Alice"}, nil
}

func main() {
    user, err := findUser(-1)
    if err != nil {
        // errors.Is: 检查错误链中是否有目标错误
        if errors.Is(err, ErrValidation) {
            fmt.Println("参数校验失败:", err)
        }

        // errors.As: 从错误链中提取特定类型
        var appErr *AppError
        if errors.As(err, &appErr) {
            fmt.Printf("应用错误码: %d\n", appErr.Code)
        }
        return
    }
    fmt.Println(user)
}

5. Goroutine 并发模型

goroutine 是 Go 的核心竞争力。一个 goroutine 只需约 2KB 内存,Go 运行时用 M:N 调度模型将数百万 goroutine 映射到操作系统线程上。

G1 (运行中)
G2 (运行中)
G3 (等待IO)
G4 (就绪)
G5 (等待Channel)
G6 (就绪)
↑ Go 运行时调度器将 goroutine 分配到 OS 线程 (P/M) 上执行
package main

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

// ─── 基础 goroutine ───────────────────────────────────────────
func basicGoroutine() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(id int) {  // 注意:传入参数避免闭包变量捕获问题
            defer wg.Done()
            time.Sleep(time.Duration(id*100) * time.Millisecond)
            fmt.Printf("goroutine %d 完成\n", id)
        }(i)
    }
    wg.Wait()
    fmt.Println("所有 goroutine 完成")
}

// ─── Channel 通信 ─────────────────────────────────────────────
func channelDemo() {
    // 无缓冲 channel: 发送者阻塞直到接收者准备好
    ch := make(chan int)
    // 有缓冲 channel: 发送不超过容量时不阻塞
    buffered := make(chan int, 10)

    // 生产者-消费者模式
    go func() {
        for i := 1; i <= 5; i++ {
            buffered <- i  // 发送
        }
        close(buffered)    // 关闭 channel,接收者会收到零值
    }()

    for v := range buffered {  // range channel: 直到关闭
        fmt.Printf("收到: %d\n", v)
    }

    _ = ch
}

// ─── Select 多路复用 ──────────────────────────────────────────
func selectDemo() {
    ch1 := make(chan string, 1)
    ch2 := make(chan string, 1)
    timeout := time.After(2 * time.Second)

    go func() {
        time.Sleep(300 * time.Millisecond)
        ch1 <- "来自 ch1"
    }()
    go func() {
        time.Sleep(500 * time.Millisecond)
        ch2 <- "来自 ch2"
    }()

    for i := 0; i < 2; i++ {
        select {
        case msg := <-ch1:
            fmt.Println("ch1:", msg)
        case msg := <-ch2:
            fmt.Println("ch2:", msg)
        case <-timeout:
            fmt.Println("超时!")
            return
        }
    }
}

// ─── Context 控制取消 ─────────────────────────────────────────
func contextDemo() {
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()

    result := make(chan string, 1)
    go func() {
        // 模拟耗时操作
        select {
        case <-time.After(2 * time.Second): // 2秒后完成
            result <- "操作完成"
        case <-ctx.Done(): // 超时或取消
            fmt.Println("操作被取消:", ctx.Err())
        }
    }()

    select {
    case r := <-result:
        fmt.Println(r)
    case <-ctx.Done():
        fmt.Println("主协程超时")
    }
}

func main() {
    basicGoroutine()
    channelDemo()
    selectDemo()
}

6. 并发安全:Mutex 与 sync 包

package main

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

// ─── 互斥锁 ───────────────────────────────────────────────────
type SafeCounter struct {
    mu sync.RWMutex
    v  map[string]int
}

func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()         // 写锁
    defer c.mu.Unlock()
    c.v[key]++
}

func (c *SafeCounter) Value(key string) int {
    c.mu.RLock()        // 读锁 (允许并发读)
    defer c.mu.RUnlock()
    return c.v[key]
}

// ─── atomic 原子操作 (比 Mutex 更快) ─────────────────────────
var requestCount atomic.Int64

func handleRequest() {
    requestCount.Add(1)
}

// ─── sync.Once 单例初始化 ──────────────────────────────────────
var (
    instance *Database
    once     sync.Once
)

func GetDB() *Database {
    once.Do(func() {  // 保证只执行一次,即使并发调用
        instance = &Database{conn: "initialized"}
        fmt.Println("数据库连接初始化")
    })
    return instance
}

// ─── sync.Pool 对象复用 ───────────────────────────────────────
var bufferPool = sync.Pool{
    New: func() any {
        return make([]byte, 0, 4096) // 初始 4KB buffer
    },
}

func processRequest(data []byte) {
    buf := bufferPool.Get().([]byte) // 从 pool 取
    defer func() {
        buf = buf[:0]           // 清空但保留容量
        bufferPool.Put(buf)    // 还回 pool
    }()
    buf = append(buf, data...)
    // 处理 buf...
}

type Database struct{ conn string }

func main() {
    counter := &SafeCounter{v: make(map[string]int)}
    var wg sync.WaitGroup

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

7. 接口与泛型

package main

import "fmt"

// ─── 接口:Go 的多态核心 ──────────────────────────────────────
type Cache interface {
    Get(key string) (any, bool)
    Set(key string, value any)
    Delete(key string)
}

// 内存缓存实现
type MemCache struct {
    data map[string]any
    mu   sync.RWMutex
}

func (m *MemCache) Get(key string) (any, bool) {
    m.mu.RLock()
    defer m.mu.RUnlock()
    v, ok := m.data[key]
    return v, ok
}

func (m *MemCache) Set(key string, value any) {
    m.mu.Lock()
    defer m.mu.Unlock()
    m.data[key] = value
}

func (m *MemCache) Delete(key string) {
    m.mu.Lock()
    defer m.mu.Unlock()
    delete(m.data, key)
}

// 使用接口,不依赖具体实现 (依赖倒置)
type UserService struct {
    cache Cache  // 可以换成 RedisCache, MemCache...
}

// ─── 泛型 (Go 1.18+) ──────────────────────────────────────────
// 泛型函数
func Map[T, U any](s []T, fn func(T) U) []U {
    result := make([]U, len(s))
    for i, v := range s {
        result[i] = fn(v)
    }
    return result
}

func Filter[T any](s []T, fn func(T) bool) []T {
    var result []T
    for _, v := range s {
        if fn(v) {
            result = append(result, v)
        }
    }
    return result
}

// 泛型类型约束
type Number interface {
    ~int | ~int64 | ~float32 | ~float64
}

func Sum[T Number](nums []T) T {
    var total T
    for _, n := range nums {
        total += n
    }
    return total
}

// 泛型结构体:类型安全的结果类型
type Result[T any] struct {
    Data  T
    Error error
}

func (r Result[T]) Unwrap() T {
    if r.Error != nil {
        panic(r.Error)
    }
    return r.Data
}

func main() {
    nums := []int{1, 2, 3, 4, 5}
    doubled := Map(nums, func(n int) int { return n * 2 })
    evens := Filter(nums, func(n int) bool { return n%2 == 0 })
    total := Sum(nums)

    fmt.Println("doubled:", doubled)   // [2 4 6 8 10]
    fmt.Println("evens:", evens)       // [2 4]
    fmt.Println("sum:", total)         // 15
}

8. 构建完整 HTTP 服务

整合以上所有知识,构建一个带有中间件、优雅关机、配置管理的完整 HTTP 服务。

package main

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

// ─── 配置 ─────────────────────────────────────────────────────
type Config struct {
    Port         string
    ReadTimeout  time.Duration
    WriteTimeout time.Duration
    IdleTimeout  time.Duration
}

func defaultConfig() Config {
    return Config{
        Port:         getEnv("PORT", "8080"),
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
        IdleTimeout:  30 * time.Second,
    }
}

func getEnv(key, defaultVal string) string {
    if v := os.Getenv(key); v != "" {
        return v
    }
    return defaultVal
}

// ─── 响应助手 ─────────────────────────────────────────────────
type APIResponse struct {
    Success bool   `json:"success"`
    Data    any    `json:"data,omitempty"`
    Error   string `json:"error,omitempty"`
}

func writeJSON(w http.ResponseWriter, status int, data any) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    json.NewEncoder(w).Encode(data)
}

func writeError(w http.ResponseWriter, status int, msg string) {
    writeJSON(w, status, APIResponse{Success: false, Error: msg})
}

// ─── 中间件 ───────────────────────────────────────────────────
func loggingMiddleware(logger *slog.Logger) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            rw := &responseWriter{ResponseWriter: w, status: 200}
            next.ServeHTTP(rw, r)
            logger.Info("request",
                "method", r.Method,
                "path", r.URL.Path,
                "status", rw.status,
                "duration", time.Since(start).String(),
                "ip", r.RemoteAddr,
            )
        })
    }
}

type responseWriter struct {
    http.ResponseWriter
    status int
}

func (rw *responseWriter) WriteHeader(status int) {
    rw.status = status
    rw.ResponseWriter.WriteHeader(status)
}

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 == http.MethodOptions {
            w.WriteHeader(http.StatusNoContent)
            return
        }
        next.ServeHTTP(w, r)
    })
}

// ─── 处理器 ───────────────────────────────────────────────────
func healthHandler(w http.ResponseWriter, r *http.Request) {
    writeJSON(w, http.StatusOK, map[string]any{
        "status": "healthy",
        "time":   time.Now().Format(time.RFC3339),
    })
}

// ─── 主函数:优雅关机 ─────────────────────────────────────────
func main() {
    cfg := defaultConfig()
    logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

    mux := http.NewServeMux()
    mux.HandleFunc("GET /health", healthHandler)
    mux.HandleFunc("GET /api/v1/users", func(w http.ResponseWriter, r *http.Request) {
        writeJSON(w, http.StatusOK, APIResponse{
            Success: true,
            Data:    []map[string]any{{"id": 1, "name": "Alice"}},
        })
    })

    // 组合中间件
    var handler http.Handler = mux
    handler = loggingMiddleware(logger)(handler)
    handler = corsMiddleware(handler)

    server := &http.Server{
        Addr:         ":" + cfg.Port,
        Handler:      handler,
        ReadTimeout:  cfg.ReadTimeout,
        WriteTimeout: cfg.WriteTimeout,
        IdleTimeout:  cfg.IdleTimeout,
    }

    // 在 goroutine 中启动服务
    go func() {
        logger.Info("服务器启动", "port", cfg.Port)
        if err := server.ListenAndServe(); err != http.ErrServerClosed {
            logger.Error("服务器错误", "err", err)
            os.Exit(1)
        }
    }()

    // 等待中断信号 (Ctrl+C 或 kill)
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit

    // 优雅关机:等待进行中的请求完成 (最多30秒)
    logger.Info("正在关机...")
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    if err := server.Shutdown(ctx); err != nil {
        logger.Error("强制关机", "err", err)
    }
    logger.Info("服务器已关闭")
}
🎯

Go 最佳实践速查

① 永远处理错误,不用 _ 丢弃  ② 接口应当小,单一职责  ③ 不要过早优化并发  ④ 用 context 传递超时/取消  ⑤ 日志用结构化(slog)