Blog Home
Updated: 2025 Nov 04

Go 语言完全指南

1. 核心理念

Go 设计哲学:简洁、高效、并发。放弃继承和泛型复杂性,拥抱组合和接口。

1.1. 设计原则

  • 少即是多: 25个关键字,语法简单
  • 组合优于继承: 通过嵌入实现代码复用
  • 显式优于隐式: 错误处理显式,无异常机制
  • 并发内置: goroutine和channel是一等公民
  • 快速编译: 依赖管理清晰,编译速度极快

2. 环境配置

2.1. 安装与工具链

# 安装 Go 1.23+
go version

# 环境变量
export GOPATH=$HOME/go
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

# 模块代理(国内)
export GOPROXY=https://goproxy.cn,direct

2.2. 关键工具

  • go mod: 依赖管理
  • go fmt: 代码格式化(强制统一)
  • go vet: 静态分析
  • go test: 测试框架
  • gopls: LSP语言服务器
  • golangci-lint: 集成linter

3. 基础语法

3.1. 包与导入

package main  // 可执行程序必须是main包

import (
    "fmt"           // 标准库
    "math/rand"
    _ "image/png"   // 仅执行init(),下划线导入
    . "strings"     // 点导入(不推荐,污染命名空间)
    m "mymodule"    // 别名导入
)

Tips: 未使用的导入会编译失败,使用 goimports 自动管理。

3.2. 变量与常量

// 变量声明
var a int = 10
var b = 20        // 类型推断
c := 30           // 短声明(仅函数内)

// 多变量
var x, y int = 1, 2
m, n := "hello", true

// 零值: int(0), string(""), bool(false), pointer(nil)
var z int  // z = 0

// 常量(编译时确定)
const Pi = 3.14
const (
    StatusOK = 200
    StatusNotFound = 404
)

// iota枚举器
const (
    Sunday = iota  // 0
    Monday         // 1
    Tuesday        // 2
)

Tips: 用 := 简化局部变量声明,但包级别用 var 更清晰。

3.3. 基本类型

// 数值类型
int8, int16, int32, int64, int    // 有符号
uint8, uint16, uint32, uint64, uint
byte   // uint8别名
rune   // int32别名,表示Unicode码点
float32, float64
complex64, complex128

// 字符串(UTF-8,不可变)
s := "你好"
s[0]  // 字节访问
for i, r := range s {  // rune遍历
    fmt.Printf("%d: %c\n", i, r)
}

// 类型转换(显式)
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

3.4. 复合类型

3.4.1. 数组(固定长度)

var arr [5]int
arr := [3]int{1, 2, 3}
arr := [...]int{1, 2, 3}  // 自动计算长度

// 数组是值类型
a := [2]int{1, 2}
b := a  // 复制整个数组

3.4.2. 切片(动态数组)

// 切片是引用类型,底层指向数组
s := []int{1, 2, 3}
s := make([]int, 5)      // len=5, cap=5
s := make([]int, 3, 10)  // len=3, cap=10

// 切片操作
s = append(s, 4, 5)
s2 := s[1:3]  // 左闭右开
s3 := s[:2]
s4 := s[2:]

// 复制
dst := make([]int, len(s))
copy(dst, s)

// 扩容机制: cap<256翻倍,之后增长约1.25倍

Tips: 预分配容量避免频繁扩容 make([]int, 0, expectedSize)

3.4.3. 映射(哈希表)

// 创建
m := make(map[string]int)
m := map[string]int{"a": 1, "b": 2}

// 操作
m["c"] = 3
val := m["a"]
val, ok := m["x"]  // 检查键是否存在
delete(m, "b")

// 遍历(无序)
for k, v := range m {
    fmt.Println(k, v)
}

// map是引用类型,未初始化为nil
var m map[string]int  // nil map,不能写入
m = make(map[string]int)  // 初始化后才能用

3.4.4. 结构体

type Person struct {
    Name string
    Age  int
    addr string  // 小写私有
}

// 初始化
p1 := Person{"Alice", 30, "NYC"}
p2 := Person{Name: "Bob", Age: 25}
p3 := &Person{Name: "Carol"}  // 指针

// 匿名字段(嵌入)
type Employee struct {
    Person        // 嵌入Person
    EmployeeID int
}

e := Employee{
    Person: Person{Name: "David", Age: 28},
    EmployeeID: 1001,
}
fmt.Println(e.Name)  // 直接访问嵌入字段

// 标签(反射元数据)
type User struct {
    Name string `json:"name" db:"user_name"`
    Age  int    `json:"age" validate:"min=0,max=150"`
}

Tips: 优先使用结构体组合而非继承模拟。

3.5. 函数

3.5.1. 基础

// 多返回值
func div(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

// 命名返回值
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return  // 裸返回
}

// 可变参数
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}
sum(1, 2, 3, 4)

3.5.2. 函数类型与闭包

// 函数是一等公民
type Processor func(int) int

func apply(f Processor, x int) int {
    return f(x)
}

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

c := counter()
fmt.Println(c())  // 1
fmt.Println(c())  // 2

3.5.3. Defer

// 延迟执行,LIFO顺序
func example() {
    defer fmt.Println("1")
    defer fmt.Println("2")
    fmt.Println("3")
    // 输出: 3 2 1
}

// 常用于资源清理
func readFile(path string) error {
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    defer f.Close()  // 确保关闭

    // 读取操作...
    return nil
}

// defer参数立即求值
i := 0
defer fmt.Println(i)  // 打印0
i++

4. 方法与接口

4.1. 方法

type Rectangle struct {
    Width, Height float64
}

// 值接收者
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// 指针接收者(可修改)
func (r *Rectangle) Scale(factor float64) {
    r.Width *= factor
    r.Height *= factor
}

r := Rectangle{10, 5}
fmt.Println(r.Area())  // 50
r.Scale(2)
fmt.Println(r.Area())  // 200

Tips: 指针接收者用于: 1)修改接收者 2)大结构体避免拷贝 3)一致性(其他方法用指针时)

4.2. 接口

// 接口是隐式实现
type Shape interface {
    Area() float64
    Perimeter() float64
}

type Circle struct {
    Radius float64
}

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

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

// Circle自动实现Shape接口
var s Shape = Circle{5}

// 空接口
var any interface{}  // 可接收任何类型
any = 42
any = "hello"

4.2.1. 类型断言与类型开关

// 类型断言
var i interface{} = "hello"
s := i.(string)          // 直接断言,失败panic
s, ok := i.(string)      // 安全断言

// 类型开关
func describe(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("int: %d\n", v)
    case string:
        fmt.Printf("string: %s\n", v)
    case Shape:
        fmt.Printf("area: %f\n", v.Area())
    default:
        fmt.Printf("unknown type\n")
    }
}

4.2.2. 常用接口

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

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

// fmt.Stringer
type Stringer interface {
    String() string
}

// error
type error interface {
    Error() string
}

设计理念: 接口小而精,单一职责。标准库多是1-3方法接口。

5. 错误处理

5.1. 基础错误

// 创建错误
err := errors.New("something went wrong")
err := fmt.Errorf("failed to process: %s", filename)

// 检查错误
result, err := doSomething()
if err != nil {
    return err  // 向上传播
}

// 包装错误(Go 1.13+)
if err != nil {
    return fmt.Errorf("operation failed: %w", err)
}

5.2. 错误检查与包装

import "errors"

// errors.Is: 判断错误链中是否包含特定错误
var ErrNotFound = errors.New("not found")

if errors.Is(err, ErrNotFound) {
    // 处理未找到
}

// errors.As: 提取特定类型错误
type ValidationError struct {
    Field string
    Msg   string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Msg)
}

var valErr *ValidationError
if errors.As(err, &valErr) {
    fmt.Println(valErr.Field)
}

5.3. 自定义错误

type PathError struct {
    Op   string
    Path string
    Err  error
}

func (e *PathError) Error() string {
    return e.Op + " " + e.Path + ": " + e.Err.Error()
}

func (e *PathError) Unwrap() error {
    return e.Err  // 支持errors.Is/As
}

Tips:

  • 不要忽略错误: result, _ : doSomething()= 应谨慎使用
  • 错误消息小写开头,无标点结尾
  • Panic仅用于不可恢复错误,库函数应返回error

6. 并发编程

6.1. Goroutine

// 启动goroutine
go func() {
    fmt.Println("异步执行")
}()

// 传递参数
for i := 0; i < 3; i++ {
    go func(n int) {  // 避免闭包陷阱
        fmt.Println(n)
    }(i)
}

// 等待goroutine(不推荐,用WaitGroup)
time.Sleep(time.Second)

Tips: Goroutine开销约2KB,可轻松启动百万级。

6.2. Channel

// 创建
ch := make(chan int)       // 无缓冲
ch := make(chan int, 10)   // 缓冲10

// 发送与接收
ch <- 42      // 发送
val := <-ch   // 接收
val, ok := <-ch  // ok为false表示channel已关闭

// 关闭channel
close(ch)

// range遍历(直到关闭)
for val := range ch {
    fmt.Println(val)
}

// 单向channel
func producer(ch chan<- int) {  // 只能发送
    ch <- 1
}

func consumer(ch <-chan int) {  // 只能接收
    val := <-ch
}

6.2.1. Select多路复用

select {
case msg := <-ch1:
    fmt.Println("ch1:", msg)
case msg := <-ch2:
    fmt.Println("ch2:", msg)
case ch3 <- 42:
    fmt.Println("sent to ch3")
case <-time.After(time.Second):
    fmt.Println("timeout")
default:
    fmt.Println("非阻塞操作")
}

6.2.2. 常用并发模式

// 1. 生产者-消费者
func producer(ch chan<- int) {
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
}

func consumer(ch <-chan int, done chan<- bool) {
    for val := range ch {
        fmt.Println(val)
    }
    done <- true
}

// 2. Fan-out/Fan-in
func fanOut(in <-chan int, workers int) []<-chan int {
    outs := make([]<-chan int, workers)
    for i := 0; i < workers; i++ {
        outs[i] = worker(in)
    }
    return outs
}

func fanIn(channels ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup

    for _, ch := range channels {
        wg.Add(1)
        go func(c <-chan int) {
            defer wg.Done()
            for v := range c {
                out <- v
            }
        }(ch)
    }

    go func() {
        wg.Wait()
        close(out)
    }()

    return out
}

// 3. Pipeline
func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

func sq(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

// 使用: gen -> sq -> print
for n := range sq(gen(2, 3, 4)) {
    fmt.Println(n)
}

6.3. Sync包

6.3.1. WaitGroup

var wg sync.WaitGroup

for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        fmt.Println(id)
    }(i)
}

wg.Wait()  // 等待所有goroutine完成

6.3.2. Mutex

type SafeCounter struct {
    mu    sync.Mutex
    count int
}

func (c *SafeCounter) Inc() {
    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 Cache struct {
    mu   sync.RWMutex
    data map[string]string
}

func (c *Cache) Get(key string) string {
    c.mu.RLock()         // 读锁
    defer c.mu.RUnlock()
    return c.data[key]
}

func (c *Cache) Set(key, val string) {
    c.mu.Lock()          // 写锁
    defer c.mu.Unlock()
    c.data[key] = val
}

6.3.3. Once

var once sync.Once

func initDB() {
    once.Do(func() {
        // 仅执行一次,线程安全
        fmt.Println("Initializing DB")
    })
}

6.3.4. Atomic

import "sync/atomic"

var counter int64

atomic.AddInt64(&counter, 1)
val := atomic.LoadInt64(&counter)
atomic.StoreInt64(&counter, 100)
swapped := atomic.CompareAndSwapInt64(&counter, 100, 200)

6.4. Context

// 1. 取消信号
ctx, cancel := context.WithCancel(context.Background())
go func() {
    select {
    case <-ctx.Done():
        fmt.Println("canceled")
    }
}()
cancel()  // 触发取消

// 2. 超时
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

// 3. 截止时间
deadline := time.Now().Add(5 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()

// 4. 传递值(谨慎使用)
ctx := context.WithValue(context.Background(), "userID", 123)
userID := ctx.Value("userID").(int)

// 传递到函数
func doWork(ctx context.Context) error {
    select {
    case <-ctx.Done():
        return ctx.Err()  // context.Canceled 或 context.DeadlineExceeded
    case <-time.After(1 * time.Second):
        return nil
    }
}

设计原则: Context应作为第一个参数,不要存储在结构体中。

7. 泛型 (Go 1.18+)

7.1. 类型参数

// 泛型函数
func Min[T constraints.Ordered](a, b T) T {
    if a < b {
        return a
    }
    return b
}

Min(1, 2)      // int
Min(1.5, 2.3)  // float64

// 泛型类型
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) {
    if len(s.items) == 0 {
        var zero T
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

// 使用
intStack := Stack[int]{}
intStack.Push(1)
val, ok := intStack.Pop()

7.2. 类型约束

// 自定义约束
type Number interface {
    int | int64 | float64
}

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

// 近似约束(底层类型)
type MyInt int

type Integer interface {
    ~int | ~int64  // ~表示底层类型
}

// 方法约束
type Stringer[T any] interface {
    String() string
}

Tips: 泛型用于数据结构和算法,不要过度使用。接口通常更灵活。

8. 包管理与模块

8.1. Go Modules

# 初始化模块
go mod init github.com/user/project

# 添加依赖(自动)
import "github.com/gin-gonic/gin"
go mod tidy  # 整理依赖

# 查看依赖
go list -m all
go mod graph

# 升级依赖
go get -u github.com/gin-gonic/gin
go get github.com/gin-gonic/gin@v1.8.0  # 特定版本

# vendor目录(可选)
go mod vendor

8.2. go.mod结构

module github.com/user/project

go 1.23

require (
    github.com/gin-gonic/gin v1.9.0
    golang.org/x/sync v0.5.0
)

require (
    // 间接依赖
    github.com/gin-contrib/sse v0.1.0 // indirect
)

replace (
    // 替换依赖(本地开发)
    github.com/old/module => github.com/new/module v1.0.0
    github.com/local/module => ../local/module
)

exclude github.com/broken/module v1.2.3

8.3. 工作区 (Go 1.18+)

# 多模块开发
go work init ./module1 ./module2
go work use ./module3

9. 测试

9.1. 单元测试

// math.go
package math

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

// math_test.go
package math

import "testing"

func TestAdd(t *testing.T) {
    result := Add(2, 3)
    expected := 5
    if result != expected {
        t.Errorf("Add(2, 3) = %d; want %d", result, expected)
    }
}

// 表驱动测试
func TestAddTable(t *testing.T) {
    tests := []struct {
        name string
        a, b int
        want int
    }{
        {"positive", 2, 3, 5},
        {"negative", -1, 1, 0},
        {"zero", 0, 0, 0},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Add(tt.a, tt.b)
            if got != tt.want {
                t.Errorf("got %d, want %d", got, tt.want)
            }
        })
    }
}

9.2. 基准测试

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(2, 3)
    }
}

// 运行: go test -bench=. -benchmem

9.3. 示例测试

func ExampleAdd() {
    fmt.Println(Add(2, 3))
    // Output: 5
}

9.4. Mock与接口

// 使用接口便于测试
type UserService interface {
    GetUser(id int) (*User, error)
}

// 生产实现
type DBUserService struct{}

func (s *DBUserService) GetUser(id int) (*User, error) {
    // 数据库查询
}

// 测试Mock
type MockUserService struct {
    users map[int]*User
}

func (s *MockUserService) GetUser(id int) (*User, error) {
    return s.users[id], nil
}

9.5. 测试覆盖率

go test -cover
go test -coverprofile=coverage.out
go tool cover -html=coverage.out

10. 反射与unsafe

10.1. 反射基础

import "reflect"

func inspect(x interface{}) {
    v := reflect.ValueOf(x)
    t := reflect.TypeOf(x)

    fmt.Println("Type:", t)
    fmt.Println("Kind:", v.Kind())

    // 获取值
    if v.Kind() == reflect.Int {
        fmt.Println("Value:", v.Int())
    }
}

// 修改值
func modify(x interface{}) {
    v := reflect.ValueOf(x)
    if v.Kind() != reflect.Ptr {
        return
    }

    v = v.Elem()  // 解引用
    if v.CanSet() {
        v.SetInt(100)
    }
}

i := 42
modify(&i)  // i = 100

10.2. 结构体反射

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func inspectStruct(x interface{}) {
    t := reflect.TypeOf(x)
    v := reflect.ValueOf(x)

    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        value := v.Field(i)
        tag := field.Tag.Get("json")

        fmt.Printf("%s (%s) = %v, tag: %s\n",
            field.Name, field.Type, value.Interface(), tag)
    }
}

10.3. Unsafe

import "unsafe"

// 指针转换(危险)
var i int64 = 42
ptr := unsafe.Pointer(&i)
floatPtr := (*float64)(ptr)  // 类型不安全

// 获取结构体字段偏移
type Person struct {
    Name string
    Age  int
}

offset := unsafe.Offsetof(Person{}.Age)

// Sizeof
size := unsafe.Sizeof(Person{})

警告: unsafe破坏类型安全和内存安全,仅用于性能关键场景。

11. 高级特性

11.1. 嵌入文件 (Go 1.16+)

import _ "embed"

//go:embed version.txt
var version string

//go:embed templates/*.html
var templates embed.FS

func loadTemplate() {
    data, _ := templates.ReadFile("templates/index.html")
}

11.2. 构建标签

//go:build linux && amd64
// +build linux,amd64  // 旧语法

package platform

func init() {
    // Linux AMD64专用代码
}

11.3. CGO

/*
#include <stdlib.h>

int add(int a, int b) {
    return a + b;
}
*/
import "C"

func main() {
    result := C.add(1, 2)
    fmt.Println(result)
}

Tips: CGO牺牲跨平台和编译速度,尽量避免。

11.4. 汇编优化

// add_amd64.s
TEXT ·Add(SB), NOSPLIT, $0-24
    MOVQ a+0(FP), AX
    MOVQ b+8(FP), BX
    ADDQ BX, AX
    MOVQ AX, ret+16(FP)
    RET

// add.go
//go:noescape
func Add(a, b int) int

12. 性能优化

12.1. Profiling

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

// CPU profiling
f, _ := os.Create("cpu.prof")
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()

// 内存profiling
f, _ := os.Create("mem.prof")
pprof.WriteHeapProfile(f)

// HTTP服务自动暴露
import _ "net/http/pprof"
go func() {
    http.ListenAndServe("localhost:6060", nil)
}()

// 访问: http://localhost:6060/debug/pprof/
// 分析: go tool pprof http://localhost:6060/debug/pprof/profile

12.2. 性能优化技巧

// 1. 避免不必要的内存分配
// 差: 频繁分配
for i := 0; i < 1000; i++ {
    s := make([]int, 100)
    // ...
}

// 好: 复用
s := make([]int, 100)
for i := 0; i < 1000; i++ {
    s = s[:0]  // 重置长度,保留容量
    // ...
}

// 2. 字符串拼接
// 差: + 操作符
var result string
for i := 0; i < 1000; i++ {
    result += "a"  // O(n²)
}

// 好: strings.Builder
var builder strings.Builder
builder.Grow(1000)  // 预分配
for i := 0; i < 1000; i++ {
    builder.WriteString("a")
}
result := builder.String()

// 3. 结构体对齐
// 差: 24字节(因填充)
type Bad struct {
    a bool   // 1 + 7填充
    b int64  // 8
    c bool   // 1 + 7填充
}

// 好: 16字节
type Good struct {
    b int64  // 8
    a bool   // 1
    c bool   // 1 + 6填充
}

// 4. 同步池
var bufferPool = sync.Pool{
    New: func() interface{} {
        return new(bytes.Buffer)
    },
}

buf := bufferPool.Get().(*bytes.Buffer)
buf.Reset()
defer bufferPool.Put(buf)

// 5. 避免interface{}装箱
// 差: 装箱开销
func processInterface(x interface{}) {
    // 类型断言开销
}

// 好: 泛型
func process[T any](x T) {
    // 无装箱
}

12.3. Benchmark优化示例

// 优化前
func Concat(strs []string) string {
    var result string
    for _, s := range strs {
        result += s
    }
    return result
}

// 优化后
func ConcatOptimized(strs []string) string {
    var builder strings.Builder
    totalLen := 0
    for _, s := range strs {
        totalLen += len(s)
    }
    builder.Grow(totalLen)
    for _, s := range strs {
        builder.WriteString(s)
    }
    return builder.String()
}

// Benchmark显示10x+性能提升

13. 标准库精选

13.1. I/O操作

import (
    "bufio"
    "io"
    "os"
)

// 读文件
data, err := os.ReadFile("file.txt")

// 写文件
err := os.WriteFile("file.txt", data, 0644)

// 流式读取
f, _ := os.Open("large.txt")
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
    line := scanner.Text()
    // 处理每行
}

// 流式写入
f, _ := os.Create("output.txt")
defer f.Close()
writer := bufio.NewWriter(f)
writer.WriteString("Hello\n")
writer.Flush()

// io.Copy
src, _ := os.Open("src.txt")
dst, _ := os.Create("dst.txt")
io.Copy(dst, src)

// MultiReader
r1 := strings.NewReader("first ")
r2 := strings.NewReader("second")
r := io.MultiReader(r1, r2)
io.Copy(os.Stdout, r)

13.2. JSON处理

import "encoding/json"

type User struct {
    ID        int    `json:"id"`
    Name      string `json:"name"`
    Email     string `json:"email,omitempty"`
    Password  string `json:"-"`  // 忽略
    CreatedAt time.Time `json:"created_at"`
}

// 序列化
user := User{ID: 1, Name: "Alice"}
data, err := json.Marshal(user)
// 格式化
data, err := json.MarshalIndent(user, "", "  ")

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

// 流式处理
encoder := json.NewEncoder(os.Stdout)
encoder.Encode(user)

decoder := json.NewDecoder(os.Stdin)
decoder.Decode(&user)

// 自定义序列化
func (u User) MarshalJSON() ([]byte, error) {
    type Alias User
    return json.Marshal(&struct {
        *Alias
        Type string `json:"type"`
    }{
        Alias: (*Alias)(&u),
        Type:  "user",
    })
}

13.3. HTTP服务

import (
    "net/http"
    "time"
)

// 简单服务器
func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello World"))
    })

    http.ListenAndServe(":8080", nil)
}

// 自定义路由
mux := http.NewServeMux()
mux.HandleFunc("/users", handleUsers)
mux.HandleFunc("/posts", handlePosts)

// 中间件
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 %v", r.Method, r.URL.Path, time.Since(start))
    })
}

// 配置服务器
server := &http.Server{
    Addr:           ":8080",
    Handler:        loggingMiddleware(mux),
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
}
server.ListenAndServe()

// HTTP客户端
client := &http.Client{
    Timeout: 30 * time.Second,
}
resp, err := client.Get("https://api.example.com/data")
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)

// POST请求
data := []byte(`{"name":"Alice"}`)
resp, err := client.Post("https://api.example.com/users",
    "application/json", bytes.NewBuffer(data))

13.4. 时间处理

import "time"

// 当前时间
now := time.Now()

// 解析时间
t, _ := time.Parse("2006-01-02 15:04:05", "2025-01-15 10:30:00")
t, _ := time.Parse(time.RFC3339, "2025-01-15T10:30:00Z")

// 格式化(使用参考时间: Mon Jan 2 15:04:05 MST 2006)
str := now.Format("2006-01-02 15:04:05")
str := now.Format(time.RFC3339)

// 时间运算
tomorrow := now.Add(24 * time.Hour)
nextWeek := now.AddDate(0, 0, 7)
duration := t2.Sub(t1)

// 定时器
timer := time.NewTimer(5 * time.Second)
<-timer.C  // 5秒后触发

// Ticker
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for t := range ticker.C {
    fmt.Println("Tick at", t)
}

// 超时控制
select {
case result := <-ch:
    // 处理结果
case <-time.After(5 * time.Second):
    // 超时
}

13.5. 正则表达式

import "regexp"

// 编译正则(缓存)
re := regexp.MustCompile(`\d{3}-\d{4}`)

// 匹配
matched := re.MatchString("123-4567")

// 查找
result := re.FindString("Call 123-4567 or 890-1234")
results := re.FindAllString("...", -1)

// 捕获组
re := regexp.MustCompile(`(\w+)@(\w+\.\w+)`)
matches := re.FindStringSubmatch("user@example.com")
// matches[0]: 完整匹配
// matches[1]: user
// matches[2]: example.com

// 替换
re := regexp.MustCompile(`\d+`)
result := re.ReplaceAllString("Age: 25", "XX")  // "Age: XX"

13.6. 数据库操作

import "database/sql"
import _ "github.com/lib/pq"  // PostgreSQL驱动

// 连接
db, err := sql.Open("postgres", "user=postgres dbname=mydb")
defer db.Close()

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

// 查询单行
var name string
var age int
err := db.QueryRow("SELECT name, age FROM users WHERE id = $1", 1).Scan(&name, &age)

// 查询多行
rows, err := db.Query("SELECT id, name FROM users WHERE age > $1", 18)
defer rows.Close()

for rows.Next() {
    var id int
    var name string
    rows.Scan(&id, &name)
    fmt.Println(id, name)
}

// 插入
result, err := db.Exec("INSERT INTO users (name, age) VALUES ($1, $2)", "Alice", 25)
id, _ := result.LastInsertId()
affected, _ := result.RowsAffected()

// 事务
tx, err := db.Begin()
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
_, err = tx.Exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
if err != nil {
    tx.Rollback()
    return err
}
tx.Commit()

// Prepared Statement
stmt, err := db.Prepare("SELECT name FROM users WHERE id = $1")
defer stmt.Close()
stmt.QueryRow(1).Scan(&name)

14. 项目结构

14.1. 标准布局

myproject/
├── cmd/                    # 主程序入口
│   ├── server/
│   │   └── main.go
│   └── cli/
│       └── main.go
├── internal/               # 私有代码(不可被外部导入)
│   ├── app/
│   ├── pkg/
│   └── config/
├── pkg/                    # 公开库代码(可被外部导入)
│   ├── api/
│   └── util/
├── api/                    # API定义(OpenAPI/gRPC)
├── web/                    # 静态资源
├── configs/                # 配置文件
├── scripts/                # 脚本
├── test/                   # 额外测试
├── docs/                   # 文档
├── examples/               # 示例
├── go.mod
├── go.sum
├── Makefile
└── README.md

14.2. 分层架构示例

// internal/domain/user.go - 领域模型
package domain

type User struct {
    ID        int
    Username  string
    Email     string
    CreatedAt time.Time
}

// internal/repository/user_repository.go - 数据访问
package repository

type UserRepository interface {
    Create(user *domain.User) error
    FindByID(id int) (*domain.User, error)
    FindByEmail(email string) (*domain.User, error)
}

type userRepository struct {
    db *sql.DB
}

func NewUserRepository(db *sql.DB) UserRepository {
    return &userRepository{db: db}
}

// internal/service/user_service.go - 业务逻辑
package service

type UserService struct {
    repo repository.UserRepository
}

func NewUserService(repo repository.UserRepository) *UserService {
    return &UserService{repo: repo}
}

func (s *UserService) Register(username, email string) (*domain.User, error) {
    // 业务逻辑
    existing, _ := s.repo.FindByEmail(email)
    if existing != nil {
        return nil, errors.New("email already exists")
    }

    user := &domain.User{
        Username:  username,
        Email:     email,
        CreatedAt: time.Now(),
    }

    if err := s.repo.Create(user); err != nil {
        return nil, err
    }

    return user, nil
}

// internal/handler/user_handler.go - HTTP处理器
package handler

type UserHandler struct {
    service *service.UserService
}

func NewUserHandler(service *service.UserService) *UserHandler {
    return &UserHandler{service: service}
}

func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) {
    var req struct {
        Username string `json:"username"`
        Email    string `json:"email"`
    }

    json.NewDecoder(r.Body).Decode(&req)

    user, err := h.service.Register(req.Username, req.Email)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

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

// cmd/server/main.go - 主程序
package main

func main() {
    db := setupDatabase()

    userRepo := repository.NewUserRepository(db)
    userService := service.NewUserService(userRepo)
    userHandler := handler.NewUserHandler(userService)

    http.HandleFunc("/register", userHandler.Register)
    http.ListenAndServe(":8080", nil)
}

15. 最佳实践

15.1. 编码规范

// 1. 命名
// 包名: 小写单数,简短有意义
package user

// 导出标识符: 大写开头
func ProcessData() {}

// 私有标识符: 小写开头
func helperFunction() {}

// 接口: -er结尾
type Reader interface {}
type Closer interface {}

// 2. 注释
// 包注释(package前)
// Package user provides user management functionality.
package user

// 导出标识符必须有注释(以名称开头)
// ProcessData processes the input data and returns the result.
func ProcessData() {}

// 3. 错误处理
// 提前返回
if err != nil {
    return err
}
// 继续正常逻辑

// 不要忽略错误
result, err := doSomething()
if err != nil {
    return nil, fmt.Errorf("failed to do something: %w", err)
}

// 4. 接口设计
// 小而精
type Reader interface {
    Read(p []byte) (n int, err error)
}

// 消费者定义接口,生产者实现
// (在使用方定义需要的接口,而非提供方)

// 5. 并发
// 使用context传递取消信号
func doWork(ctx context.Context) error {
    select {
    case <-ctx.Done():
        return ctx.Err()
    case <-workDone:
        return nil
    }
}

// channel由发送方关闭
ch := make(chan int)
go func() {
    defer close(ch)
    for i := 0; i < 10; i++ {
        ch <- i
    }
}()

// 6. 初始化
// 使用构造函数
func NewServer(addr string) *Server {
    return &Server{
        addr: addr,
        mux:  http.NewServeMux(),
    }
}

// 避免init(),除非必要(如注册驱动)

15.2. 常见陷阱

// 1. 循环变量捕获
for _, v := range values {
    go func() {
        fmt.Println(v)  // 错误: v被共享
    }()
}

// 正确:
for _, v := range values {
    v := v  // 创建副本
    go func() {
        fmt.Println(v)
    }()
}

// 或传参:
for _, v := range values {
    go func(val int) {
        fmt.Println(val)
    }(v)
}

// 2. Slice陷阱
s1 := []int{1, 2, 3, 4, 5}
s2 := s1[1:3]  // [2, 3]
s2[0] = 999    // s1变为[1, 999, 3, 4, 5]

// 完全复制:
s2 := make([]int, len(s1))
copy(s2, s1)

// 3. Map并发读写
m := make(map[string]int)
go func() { m["a"] = 1 }()
go func() { m["b"] = 2 }()  // 竞态条件!

// 使用sync.Map或加锁

// 4. Defer在循环中
for _, file := range files {
    f, _ := os.Open(file)
    defer f.Close()  // 循环结束后才执行,可能耗尽文件描述符
}

// 正确: 使用函数封装
for _, file := range files {
    func() {
        f, _ := os.Open(file)
        defer f.Close()
        // 处理文件
    }()
}

// 5. nil interface
var p *int = nil
var i interface{} = p
fmt.Println(i == nil)  // false! interface包含类型信息

// 6. Goroutine泄漏
func leak() {
    ch := make(chan int)
    go func() {
        val := <-ch  // 永远阻塞,goroutine泄漏
        fmt.Println(val)
    }()
    // 忘记发送数据
}

// 使用context取消
func noLeak(ctx context.Context) {
    ch := make(chan int)
    go func() {
        select {
        case val := <-ch:
            fmt.Println(val)
        case <-ctx.Done():
            return
        }
    }()
}

16. 工具链使用

16.1. 常用命令

# 格式化
go fmt ./...
goimports -w .

# 静态分析
go vet ./...
golangci-lint run

# 构建
go build -o myapp ./cmd/myapp
go build -ldflags="-s -w" -o myapp  # 压缩二进制

# 交叉编译
GOOS=linux GOARCH=amd64 go build
GOOS=windows GOARCH=amd64 go build

# 运行
go run ./cmd/myapp

# 测试
go test ./...
go test -v -cover ./...
go test -race ./...  # 竞态检测
go test -bench=. -benchmem

# 性能分析
go test -cpuprofile=cpu.prof -memprofile=mem.prof
go tool pprof cpu.prof

# 依赖管理
go mod init
go mod tidy
go mod download
go mod verify
go get -u ./...  # 升级所有依赖

# 文档
go doc fmt.Println
godoc -http=:6060

# 代码生成
go generate ./...

16.2. Makefile示例

.PHONY: build test clean

APP_NAME=myapp
BUILD_DIR=bin

build:
        go build -o $(BUILD_DIR)/$(APP_NAME) ./cmd/$(APP_NAME)

test:
        go test -v -cover ./...

test-race:
        go test -race ./...

bench:
        go test -bench=. -benchmem ./...

lint:
        golangci-lint run

fmt:
        gofmt -s -w .
        goimports -w .

clean:
        rm -rf $(BUILD_DIR)

run:
        go run ./cmd/$(APP_NAME)

docker:
        docker build -t $(APP_NAME):latest .

.DEFAULT_GOAL := build

16.3. Dockerfile最佳实践

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

WORKDIR /app

# 缓存依赖
COPY go.mod go.sum ./
RUN go mod download

# 构建
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/server

# 最小运行镜像
FROM alpine:latest

RUN apk --no-cache add ca-certificates
WORKDIR /root/

COPY --from=builder /app/main .
COPY --from=builder /app/configs ./configs

EXPOSE 8080
CMD ["./main"]

17. 进阶主题

17.1. 内存模型

Go保证:

  1. 单goroutine内,读写顺序与代码顺序一致
  2. Init函数在main前执行
  3. Goroutine创建happens-before其执行
  4. Channel发送happens-before接收完成
  5. Mutex.Unlock() happens-before后续Lock()

17.2. 逃逸分析

// 栈分配
func stack() int {
    x := 42
    return x
}

// 堆分配(逃逸)
func heap() *int {
    x := 42
    return &x  // x逃逸到堆
}

// 查看逃逸分析
// go build -gcflags="-m" main.go

优化技巧:

  • 避免返回局部变量指针
  • 减少interface{}使用
  • 预分配slice容量

17.3. 编译器指令

//go:noinline       // 禁止内联
//go:nosplit        // 禁止栈分裂
//go:noescape       // 参数不逃逸
//go:linkname       // 链接到其他符号
//go:generate       // 代码生成
//go:embed          // 嵌入文件

//go:generate go run gen.go
//go:generate mockgen -source=interface.go -destination=mock.go

18. 总结

18.1. 学习路径

  1. 基础语法 → 2. 并发编程 → 3. 标准库 → 4. 项目实战 → 5. 性能优化

18.2. 推荐资源

18.3. 关键要点

  • 简洁至上: 选择最简单的解决方案
  • 显式错误处理: 不要忽略错误
  • 组合优于继承: 使用接口和嵌入
  • 并发安全: 通过channel通信,不要共享内存
  • 性能意识: 了解内存分配和逃逸分析
  • 测试先行: 良好的测试覆盖率
  • 标准工具: 使用go fmt, go vet等标准工具

Go的哲学是"少即是多",避免过度设计,写清晰简洁的代码。

Comments:

Email questions, comments, and corrections to hi@smartisan.dev.

Submissions may appear publicly on this website, unless requested otherwise in your email.