第 3 章 · 流程控制与函数
本章目标:掌握 if、for(Go 无 while)、switch、range;编写多返回值函数与命名返回值;理解闭包基础与 defer 预告;在 toolkit-go 实现订单金额计算与慢日志分类;对照 java-dev ch03 控制流与 python-dev ch03 循环语法。
学时建议:3~4 小时(含 1.5 小时跟练)
前置:完成 go-dev ch02;建议已学 java-dev ch03 或 python-dev ch03。
3.1 场景说明:计算订单与过滤慢日志
toolkit-go(~/learn-go/toolkit-go,模块 example.com/toolkit-go)在解析 access 日志时需要:
| 任务 | 控制结构 | 所在包 |
|---|---|---|
| 按耗时阈值标记慢请求 | if / switch | internal/filter |
| 遍历日志行 | for + range | internal/logparser |
| 汇总订单行金额 | 函数 + 多返回值 | internal/calc |
| HTTP 状态码分类 | switch | internal/filter |
toolkit-go/
├── internal/
│ ├── calc/
│ │ └── order.go # CalcLinesTotal
│ ├── filter/
│ │ └── slow.go # IsSlowRequest, ClassifyHTTP
│ └── model/
│ └── line.go # LineItem
└── cmd/toolkit/main.go
3.2 if 语句与短变量声明
Go 的 if 可在条件前写简短语句,变量作用域限于 if-else 块。
// internal/filter/slow.go
package filter
const SlowThresholdMs = 500
func IsSlowRequest(durationMs int) bool {
if durationMs <= 0 {
return false
}
return durationMs >= SlowThresholdMs
}
func ClassifyDuration(ms int) string {
switch {
case ms < 100:
return "fast"
case ms < SlowThresholdMs:
return "normal"
default:
return "slow"
}
}
| Java | Go | Python |
|---|---|---|
if (x > 0) { } | if x > 0 { } | if x > 0: |
| 条件必须是 boolean | 条件必须是 boolean | 任意 truthy |
| 无 if 内声明 | if err := fn(); err != nil { } | 无直接等价 |
if 短语句示例(error 处理预告 ch07):
if n := len(items); n == 0 {
return fmt.Errorf("empty items")
} else if n > 100 {
return fmt.Errorf("too many: %d", n)
}
3.3 for 循环:Go 唯一的循环关键字
Go 没有 while,所有循环用 for 表达。
package calc
import "fmt"
func DemoFor() {
items := []int64{100, 200, 300}
// 经典三段式 for
for i := 0; i < len(items); i++ {
_ = items[i]
}
// while 风格
stock := 3
for stock > 0 {
stock--
}
// 无限循环(需 break / return)
for {
break
}
// range 遍历 slice
for idx, price := range items {
fmt.Println(idx, price)
}
// 只要值,忽略下标
for _, price := range items {
_ = price
}
}
| Java | Go | Python |
|---|---|---|
while (cond) | for cond { } | while cond: |
for (int i=0; ...) | for i := 0; i < n; i++ | for i in range(n) |
for (Type x : arr) | for _, x := range arr | for x in arr |
do-while | 无(用 for + break) | 无原生 |
range 遍历 map(ch04 详讲 map):
cart := map[string]int{"go-book": 2, "go-mug": 1}
for slug, qty := range cart {
_ = slug
_ = qty
}
3.4 switch 语句
Go 的 switch 默认不贯穿(每个 case 自动 break),与 Java/C 不同。
// internal/filter/http_class.go
package filter
func ClassifyHTTP(status int) string {
switch status {
case 200, 201, 204:
return "success"
case 400, 401, 403, 404:
return "client_error"
case 500, 502, 503:
return "server_error"
default:
return "unknown"
}
}
func LogLevelLabel(level string) string {
switch level {
case "debug", "trace":
return "LOW"
case "info":
return "INFO"
case "warn", "error":
return "HIGH"
default:
return "UNKNOWN"
}
}
| 特性 | 说明 |
|---|---|
| 无表达式 switch | switch { case x > 0: } 替代 if-else 链 |
| 多值 case | case 200, 201: |
fallthrough | 显式贯穿到下一 case(慎用) |
| type switch | 对 any 做类型分支(ch06 接口) |
type switch 预告:
func describe(v any) string {
switch x := v.(type) {
case int:
return fmt.Sprintf("int:%d", x)
case string:
return fmt.Sprintf("str:%s", x)
default:
return "other"
}
}
3.5 函数声明与多返回值
Go 用 error 返回值 替代异常(详见 ch07),多返回值是惯用模式。
// internal/calc/order.go
package calc
import "fmt"
type LineItem struct {
Slug string
Price int64 // 分
Quantity int
}
func Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("divide by zero")
}
return a / b, nil
}
func CalcOrderTotal(prices []int64) (total int64, err error) {
if len(prices) == 0 {
return 0, fmt.Errorf("empty order")
}
for _, p := range prices {
if p < 0 {
return 0, fmt.Errorf("negative price: %d", p)
}
total += p
}
return total, nil
}
func CalcLinesTotal(lines []LineItem) (int64, error) {
var total int64
for _, ln := range lines {
if ln.Quantity <= 0 {
return 0, fmt.Errorf("invalid qty for %s", ln.Slug)
}
total += ln.Price * int64(ln.Quantity)
}
return total, nil
}
| 模式 | 示例 | 说明 |
|---|---|---|
| 双返回 | (T, error) | 最常见错误处理 |
| 多返回 | (v, ok, err) | 查 map / 解析 |
| 命名返回 | (total int64, err error) | 短函数可读;裸 return 返回命名值 |
| 无返回 | 无括号 | 仅副作用 |
| Java | Go |
|---|---|
try/catch | if err != nil { return err } |
| 单返回值 | 多返回值 |
| 方法重载 | 无重载;用不同函数名或可选参数模式 |