🔀 第03课:控制流与函数

Go基础 第1阶段·第3/7课

📋 本课目标

🔬 代码演示与验证

package main
import ("errors";"fmt";"math")
func add(a,b int) int { return a+b }
func divide(a,b float64) (float64,error) {
    if b==0 { return 0,errors.New("除数不能为零") }
    return a/b, nil
}
func swap(a,b int) (first,second int) { first=b; second=a; return }
func sum(nums ...int) int { t:=0; for _,n:=range nums{t+=n}; return t }
func counter() func() int { c:=0; return func()int{c++;return c} }
func fib(n int) int { if n<=1{return n}; return fib(n-1)+fib(n-2) }
func main() {
    fmt.Println("=== if-else ===")
    score:=85
    if score>=90{fmt.Println("优秀")}else if score>=80{fmt.Println("良好")}else{fmt.Println("一般")}
    fmt.Println("\n=== switch ===")
    day:="Wednesday"
    switch day{case "Monday","Tuesday":fmt.Println("工作日初期");case "Wednesday":fmt.Println("周中");default:fmt.Println("其他")}
    fmt.Println("\n=== for ===")
    for i:=0;i<5;i++{fmt.Printf("%d ",i)}; fmt.Println()
    n:=1; for n<100{n*=2}; fmt.Printf("n=%d\n",n)
    fmt.Println("\n=== 函数 ===")
    fmt.Printf("add(3,5)=%d\n",add(3,5))
    r,err:=divide(10.,3.); fmt.Printf("divide(10,3)=%.2f err=%v\n",r,err)
    _,err2:=divide(10.,0); fmt.Printf("divide(10,0) err=%v\n",err2)
    a,b:=swap(1,2); fmt.Printf("swap(1,2)=%d,%d\n",a,b)
    fmt.Printf("sum(1..5)=%d\n",sum(1,2,3,4,5))
    fmt.Println("\n=== 闭包 ===")
    c:=counter(); fmt.Printf("counter: %d %d %d\n",c(),c(),c())
    fmt.Println("\n=== 递归fib ===")
    for i:=0;i<10;i++{fmt.Printf("fib(%d)=%d ",i,fib(i))}; fmt.Println()
    fmt.Println("\n=== defer LIFO ===")
    for i:=0;i<3;i++{defer fmt.Printf("defer%d ",i)}
    fmt.Println("函数体")
    fmt.Printf("\nsqrt(3)=%.4f\n",math.Sqrt(3))
}

🔍 运行验证

✅ 验证通过 — 实机运行结果:

=== if-else ===
良好

=== switch ===
周中

=== for ===
0 1 2 3 4 
n=128

=== 函数 ===
add(3,5)=8
divide(10,3)=3.33 err=<nil>
divide(10,0) err=除数不能为零
swap(1,2)=2,1
sum(1..5)=15

=== 闭包 ===
counter: 1 2 3

=== 递归fib ===
fib(0)=0 fib(1)=1 fib(2)=1 fib(3)=2 fib(4)=3 fib(5)=5 fib(6)=8 fib(7)=13 fib(8)=21 fib(9)=34 

=== defer LIFO ===
函数体

sqrt(3)=1.7321
defer2 defer1 defer0 

🧠 控制流

条件: if-else/switch 循环: for/while/range 跳转: break/continue 延迟: defer(LIFO)

🔀 switch

switch day {
case "Saturday","Sunday": fmt.Println("周末")
default: fmt.Println("工作日")
}
// 类型switch
switch v := i.(type) { case int: ... case string: ... }

⚙️ 函数

func divide(a,b float64) (float64, error) {
    if b==0 { return 0, errors.New("除零") }
    return a/b, nil
}
func sum(nums ...int) int { ... }  // 可变参数
func swap(a,b int) (first,second int) { first=b; second=a; return }

🎯 闭包

counter := func() func() int { c:=0; return func()int{c++;return c} }()
fmt.Println(counter(), counter())  // 1 2

⏳ defer

mu.Lock(); defer mu.Unlock()
file,_ := os.Open(f); defer file.Close()
// LIFO: 最后defer的最先执行

🔑 本课要点回顾

知识点关键内容
if支持初始化语句
switch自动break/fallthrough
for三段式/while/range
函数多返回值/可变参数
闭包函数值+捕获变量
deferLIFO顺序

🏋️ 练习

FizzBuzz

1-100输出Fizz/Buzz

高阶函数

mapInts/filterInts

defer追踪

进出日志

🏆

成就解锁:流程控制师!

📖 控制流深入

if初始化语句的妙用

// 常见模式:函数调用+错误检查
if err := doWork(); err != nil {
    return err  // err只在if块内可见
}

// 文件操作
if f, err := os.Open("file.txt"); err == nil {
    defer f.Close()
    // 使用f
}

// 类型断言
if v, ok := i.(string); ok {
    fmt.Println(v)
}

🔀 switch高级用法

// 无条件switch(比if-else链更清晰)
switch {
case score >= 90: grade = "A"
case score >= 80: grade = "B"
case score >= 70: grade = "C"
default: grade = "F"
}

// fallthrough穿透
switch n {
case 1:
    fmt.Println("一")
    fallthrough  // 无条件穿透到下一个case
case 2:
    fmt.Println("二")  // 即使n=1也会执行这里
}

// 类型switch
switch v := x.(type) {
case nil:       fmt.Println("nil")
case int:       fmt.Printf("int: %d
", v)
case string:    fmt.Printf("string: %s
", v)
case []int:     fmt.Printf("slice: %v
", v)
default:        fmt.Printf("unknown: %T
", v)
}

⚙️ 函数高级模式

// 函数类型作为参数
func apply(nums []int, fn func(int) int) []int {
    result := make([]int, len(nums))
    for i, n := range nums {
        result[i] = fn(n)
    }
    return result
}
doubled := apply([]int{1,2,3}, func(n int) int { return n*2 })

// 返回闭包
func makeAdder(x int) func(int) int {
    return func(y int) int { return x + y }
}
add5 := makeAdder(5)
fmt.Println(add5(3))  // 8

// 函数选项模式
type Option func(*Config)
func WithPort(p int) Option { return func(c *Config) { c.Port = p } }
func NewServer(opts ...Option) *Server {
    cfg := defaultConfig()
    for _, opt := range opts { opt(&cfg) }
    return &Server{cfg: cfg}
}

⏳ defer高级

// defer追踪函数耗时
func trace(name string) func() {
    start := time.Now()
    fmt.Printf("→ %s 开始
", name)
    return func() { fmt.Printf("← %s 完成 (%v)
", name, time.Since(start)) }
}

func myFunc() {
    defer trace("myFunc")()
    // ... 工作 ...
}

// defer参数立即求值
x := 10
defer fmt.Println(x)  // 输出10
x = 20               // 不影响defer的值

📖 延伸阅读与资源

🎯 实战开发建议

  1. 动手编码 — 只看不练等于没学,每课代码必须自己敲一遍
  2. 使用go docgo doc fmt.Printf 查看标准库文档
  3. 编写测试go test 验证你的理解是否正确
  4. 阅读源码 — 标准库是Go最佳实践的活教材
  5. 项目实战 — 在真实项目中应用所学

⚡ Go性能优化清单

// 1. 预分配切片容量 — 避免频繁扩容
s := make([]int, 0, expectedSize)

// 2. strings.Builder拼接 — 比fmt.Sprintf快3-5倍
var b strings.Builder
b.WriteString("hello")
b.WriteString(" world")
result := b.String()

// 3. sync.Pool对象复用 — 减少GC压力
var bufPool = sync.Pool{
    New: func() interface{} { return new(bytes.Buffer) },
}
buf := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buf)

// 4. 减少堆分配 — 小对象栈分配,避免逃逸
// 用 go build -gcflags="-m" 分析逃逸

// 5. 使用benchmark验证性能
func BenchmarkXxx(b *testing.B) {
    for i := 0; i < b.N; i++ {
        // 被测代码
    }
}
// go test -bench=. -benchmem

🔍 调试与排查技巧

// 1. 格式化调试输出
fmt.Printf("%+v
", myStruct)  // 带字段名
fmt.Printf("%#v
", myValue)   // Go语法表示

// 2. log包运行时日志
log.Printf("[DEBUG] value=%v", val)
log.SetFlags(log.LstdFlags | log.Lshortfile)

// 3. delve源码调试器
// 安装: go install github.com/go-delve/delve/cmd/dlv@latest
// 使用: dlv debug ./main.go
// 命令: break main.main / continue / next / print

// 4. pprof性能分析
import _ "net/http/pprof"
go http.ListenAndServe(":6060", nil)
// 访问: http://localhost:6060/debug/pprof/
// 命令: go tool pprof http://localhost:6060/debug/pprof/profile

// 5. race detector竞态检测
// go run -race main.go
// go test -race ./...

📊 Go工具生态

工具用途安装
golangci-lint代码静态检查go install github.com/golangci/golangci-lint/cmd/...@latest
gofumpt代码格式化(增强)go install mvdan.cc/gofumpt@latest
goimports自动管理importgo install golang.org/x/tools/cmd/goimports@latest
dlv源码调试器go install github.com/go-delve/delve/cmd/dlv@latest
air热重载开发go install github.com/cosmtrek/air@latest
swagSwagger文档生成go install github.com/swaggo/swag/cmd/swag@latest
migrate数据库迁移go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest

🏗️ Go项目结构最佳实践

myproject/
├── cmd/                    # 可执行程序入口
│   └── server/
│       └── main.go
├── internal/               # 私有代码(不可外部导入)
│   ├── handler/            # HTTP处理
│   ├── service/            # 业务逻辑
│   ├── repository/         # 数据访问
│   └── model/              # 数据模型
├── pkg/                    # 可复用公共包
│   └── utils/
├── api/                    # API定义(proto/openapi)
├── configs/                # 配置文件
├── scripts/                # 构建/部署脚本
├── test/                   # 集成测试
├── go.mod
├── go.sum
├── Makefile
└── Dockerfile