流程控制与函数
2026/3/20大约 14 分钟
流程控制与函数
一、条件语句
1.1 if 语句
Go 的 if 语句无需括号包围条件表达式,但花括号是必须的:
package main
import (
"fmt"
"os"
"runtime"
)
func main() {
// 基本形式
x := 10
if x > 5 {
fmt.Println("x 大于 5")
}
// if-else
if x%2 == 0 {
fmt.Println("x 是偶数")
} else {
fmt.Println("x 是奇数")
}
// if-else if-else
score := 85
if score >= 90 {
fmt.Println("优秀")
} else if score >= 80 {
fmt.Println("良好")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
// ========== if 简短语句(Go 特有)==========
// 可以在条件之前执行一个简单语句
// 该语句声明的变量只在 if 块内可用
if err := doSomething(); err != nil {
fmt.Println("操作失败:", err)
return
}
// 常见的错误处理模式
if data, err := os.ReadFile("/etc/hostname"); err != nil {
fmt.Println("读取失败:", err)
} else {
fmt.Printf("主机名: %s", data)
}
// 运维场景:系统检查
if mem := runtime.MemStats{}; true {
runtime.ReadMemStats(&mem)
allocMB := float64(mem.Alloc) / 1024 / 1024
if allocMB > 100 {
fmt.Printf("警告: 内存使用 %.2f MB\n", allocMB)
}
}
}
func doSomething() error {
return nil
}
1.2 switch 语句
Go 的 switch 比其他语言更灵活,默认不需要 break:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
// ========== 基本 switch ==========
day := time.Now().Weekday()
switch day {
case time.Saturday, time.Sunday: // 多个值匹配
fmt.Println("周末")
case time.Friday:
fmt.Println("周五,快乐的一天")
default:
fmt.Println("工作日")
}
// ========== 无条件 switch(替代 if-else 链)==========
hour := time.Now().Hour()
switch {
case hour < 6:
fmt.Println("凌晨")
case hour < 12:
fmt.Println("上午")
case hour < 18:
fmt.Println("下午")
default:
fmt.Println("晚上")
}
// ========== switch 简短语句 ==========
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS 系统")
case "linux":
fmt.Println("Linux 系统")
case "windows":
fmt.Println("Windows 系统")
default:
fmt.Printf("其他系统: %s\n", os)
}
// ========== 类型 switch ==========
var val interface{} = "hello"
switch v := val.(type) {
case nil:
fmt.Println("nil 值")
case int:
fmt.Printf("整数: %d\n", v)
case string:
fmt.Printf("字符串: %s\n", v)
case bool:
fmt.Printf("布尔: %v\n", v)
case []byte:
fmt.Printf("字节切片: %v\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
// ========== fallthrough(继续执行下一个 case)==========
level := 2
fmt.Print("权限: ")
switch level {
case 3:
fmt.Print("管理员 ")
fallthrough
case 2:
fmt.Print("编辑 ")
fallthrough
case 1:
fmt.Print("查看 ")
fallthrough
case 0:
fmt.Print("访客")
}
fmt.Println()
// 运维场景:HTTP 状态码处理
statusCode := 502
switch {
case statusCode >= 500:
fmt.Printf("[ERROR] 服务器错误: %d\n", statusCode)
case statusCode >= 400:
fmt.Printf("[WARN] 客户端错误: %d\n", statusCode)
case statusCode >= 300:
fmt.Printf("[INFO] 重定向: %d\n", statusCode)
case statusCode >= 200:
fmt.Printf("[OK] 成功: %d\n", statusCode)
default:
fmt.Printf("[UNKNOWN] 未知状态: %d\n", statusCode)
}
}
二、循环语句
Go 只有 for 一种循环结构,但非常灵活:
2.1 for 循环形式
package main
import (
"fmt"
"time"
)
func main() {
// ========== 形式一:标准 for 循环 ==========
for i := 0; i < 5; i++ {
fmt.Printf("i = %d\n", i)
}
// ========== 形式二:while 形式 ==========
count := 0
for count < 3 {
fmt.Printf("count = %d\n", count)
count++
}
// ========== 形式三:无限循环 ==========
// for {
// fmt.Println("无限循环")
// break // 需要 break 退出
// }
// ========== range 遍历 ==========
// 遍历切片
servers := []string{"web-01", "web-02", "web-03"}
for index, server := range servers {
fmt.Printf("[%d] %s\n", index, server)
}
// 只要索引
for i := range servers {
fmt.Printf("索引: %d\n", i)
}
// 只要值(使用 _ 忽略索引)
for _, server := range servers {
fmt.Println("服务器:", server)
}
// 遍历 map
config := map[string]string{
"host": "localhost",
"port": "8080",
"mode": "production",
}
for key, value := range config {
fmt.Printf("%s = %s\n", key, value)
}
// 遍历字符串(按 rune)
for i, ch := range "Go语言" {
fmt.Printf("位置 %d: %c\n", i, ch)
}
// 遍历 channel
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for v := range ch {
fmt.Println("收到:", v)
}
// ========== 运维场景:重试机制 ==========
maxRetries := 3
for attempt := 1; attempt <= maxRetries; attempt++ {
fmt.Printf("尝试第 %d 次连接...\n", attempt)
err := connectToServer()
if err == nil {
fmt.Println("连接成功")
break
}
fmt.Printf("失败: %v\n", err)
if attempt < maxRetries {
time.Sleep(time.Second * time.Duration(attempt))
}
}
}
func connectToServer() error {
return nil
}
2.2 break、continue、goto
package main
import "fmt"
func main() {
// ========== break:退出当前循环 ==========
for i := 0; i < 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
// ========== continue:跳过本次迭代 ==========
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // 跳过偶数
}
fmt.Println(i) // 只打印奇数
}
// ========== 标签(Label):用于嵌套循环 ==========
OuterLoop:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break OuterLoop // 跳出外层循环
}
fmt.Printf("i=%d, j=%d\n", i, j)
}
}
// continue 配合标签
NextServer:
for _, server := range []string{"web-01", "web-02", "web-03"} {
for _, port := range []int{80, 443, 8080} {
if server == "web-02" && port == 443 {
continue NextServer // 跳到下一个服务器
}
fmt.Printf("检查 %s:%d\n", server, port)
}
}
// ========== goto:谨慎使用 ==========
// 主要用于错误处理中的清理逻辑
if err := step1(); err != nil {
goto cleanup
}
if err := step2(); err != nil {
goto cleanup
}
fmt.Println("所有步骤完成")
return
cleanup:
fmt.Println("执行清理...")
}
func step1() error { return nil }
func step2() error { return nil }
2.3 Go 1.22 循环变量改进
Go 1.22 修复了循环变量作用域的历史问题:
package main
import (
"fmt"
"time"
)
func main() {
// Go 1.22 之前的问题
// 所有 goroutine 共享同一个 i 变量,最终都打印 3
// for i := 0; i < 3; i++ {
// go func() {
// fmt.Println(i) // 可能都是 3
// }()
// }
// Go 1.22+ 每次迭代 i 是新变量
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i) // 正确打印 0, 1, 2
}()
}
// 旧版本的解决方案(仍然适用)
for i := 0; i < 3; i++ {
i := i // 创建副本
go func() {
fmt.Println(i)
}()
}
// 或者传参
for i := 0; i < 3; i++ {
go func(n int) {
fmt.Println(n)
}(i)
}
time.Sleep(time.Second)
}
三、函数基础
3.1 函数声明
package main
import (
"fmt"
"errors"
)
// 基本函数
func greet(name string) {
fmt.Printf("Hello, %s!\n", name)
}
// 带返回值
func add(a, b int) int {
return a + b
}
// 多参数同类型简写
func sum(a, b, c int) int {
return a + b + c
}
// 多返回值(Go 特色)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
// 命名返回值
func rectangle(width, height float64) (area, perimeter float64) {
area = width * height
perimeter = 2 * (width + height)
return // 裸返回
}
// 可变参数
func sumAll(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
// 运维场景:服务健康检查
func checkHealth(host string, port int) (bool, string) {
// 模拟检查
if host == "" {
return false, "host cannot be empty"
}
if port <= 0 || port > 65535 {
return false, "invalid port number"
}
return true, "healthy"
}
func main() {
greet("Gopher")
result := add(3, 5)
fmt.Println("3 + 5 =", result)
if val, err := divide(10, 3); err != nil {
fmt.Println("错误:", err)
} else {
fmt.Printf("10 / 3 = %.2f\n", val)
}
area, peri := rectangle(4, 5)
fmt.Printf("面积: %.1f, 周长: %.1f\n", area, peri)
// 可变参数调用
fmt.Println(sumAll(1, 2, 3, 4, 5))
// 切片展开传递
nums := []int{10, 20, 30}
fmt.Println(sumAll(nums...))
// 健康检查
ok, msg := checkHealth("localhost", 8080)
fmt.Printf("健康状态: %v, 消息: %s\n", ok, msg)
}
3.2 函数类型与变量
package main
import (
"fmt"
"sort"
"strings"
)
// 函数类型定义
type MathFunc func(int, int) int
type Validator func(string) bool
type Handler func(data []byte) error
// 函数作为参数
func apply(fn MathFunc, a, b int) int {
return fn(a, b)
}
// 函数作为返回值
func getOperation(op string) MathFunc {
switch op {
case "+":
return func(a, b int) int { return a + b }
case "-":
return func(a, b int) int { return a - b }
case "*":
return func(a, b int) int { return a * b }
case "/":
return func(a, b int) int {
if b == 0 {
return 0
}
return a / b
}
default:
return nil
}
}
func main() {
// 函数变量
var fn MathFunc
fn = func(a, b int) int {
return a + b
}
fmt.Println(fn(3, 4))
// 使用 apply
result := apply(func(a, b int) int {
return a * b
}, 6, 7)
fmt.Println("6 * 7 =", result)
// 获取操作函数
addFn := getOperation("+")
fmt.Println("10 + 5 =", addFn(10, 5))
// 匿名函数立即执行
func() {
fmt.Println("立即执行的匿名函数")
}()
// 标准库中的函数参数
servers := []string{"web-03", "web-01", "web-02"}
sort.Slice(servers, func(i, j int) bool {
return servers[i] < servers[j]
})
fmt.Println(servers)
// 运维场景:自定义验证器
validators := map[string]Validator{
"notEmpty": func(s string) bool {
return strings.TrimSpace(s) != ""
},
"isIP": func(s string) bool {
parts := strings.Split(s, ".")
return len(parts) == 4
},
}
testIP := "192.168.1.1"
for name, validate := range validators {
fmt.Printf("%s(%q): %v\n", name, testIP, validate(testIP))
}
}
3.3 闭包
闭包是引用了外部变量的函数:
package main
import (
"fmt"
"sync"
)
// 计数器闭包
func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
// 累加器闭包
func makeAccumulator(initial int) func(int) int {
sum := initial
return func(delta int) int {
sum += delta
return sum
}
}
// 运维场景:创建带前缀的日志函数
func makeLogger(prefix string) func(string) {
return func(msg string) {
fmt.Printf("[%s] %s\n", prefix, msg)
}
}
// 运维场景:限流器
func makeRateLimiter(limit int) func() bool {
var (
count int
mu sync.Mutex
)
return func() bool {
mu.Lock()
defer mu.Unlock()
if count >= limit {
return false // 超过限制
}
count++
return true
}
}
// 运维场景:重试函数
func withRetry(maxRetries int, fn func() error) func() error {
return func() error {
var lastErr error
for i := 0; i < maxRetries; i++ {
if err := fn(); err == nil {
return nil
} else {
lastErr = err
fmt.Printf("重试 %d/%d: %v\n", i+1, maxRetries, err)
}
}
return fmt.Errorf("达到最大重试次数: %v", lastErr)
}
}
func main() {
// 计数器
counter := makeCounter()
fmt.Println(counter()) // 1
fmt.Println(counter()) // 2
fmt.Println(counter()) // 3
// 独立的计数器
counter2 := makeCounter()
fmt.Println(counter2()) // 1(独立)
// 累加器
acc := makeAccumulator(100)
fmt.Println(acc(10)) // 110
fmt.Println(acc(20)) // 130
// 日志函数
infoLog := makeLogger("INFO")
errorLog := makeLogger("ERROR")
infoLog("服务启动")
errorLog("连接失败")
// 限流器
limiter := makeRateLimiter(3)
for i := 0; i < 5; i++ {
if limiter() {
fmt.Printf("请求 %d 通过\n", i+1)
} else {
fmt.Printf("请求 %d 被限流\n", i+1)
}
}
}
四、defer 语句
4.1 defer 基础
defer 延迟执行函数,在外层函数返回前执行:
package main
import (
"fmt"
"os"
"sync"
)
func main() {
// 基本用法
fmt.Println("开始")
defer fmt.Println("结束1") // 最后执行
defer fmt.Println("结束2") // 倒数第二
defer fmt.Println("结束3") // 第三
fmt.Println("中间")
// 输出顺序:开始 -> 中间 -> 结束3 -> 结束2 -> 结束1
}
4.2 defer 常见用途
package main
import (
"database/sql"
"fmt"
"io"
"net/http"
"os"
"sync"
"time"
)
// 1. 资源释放 - 文件
func readFile(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close() // 确保文件关闭
return io.ReadAll(file)
}
// 2. 资源释放 - HTTP 响应
func fetchURL(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close() // 确保响应体关闭
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
// 3. 解锁互斥锁
type SafeCounter struct {
mu sync.Mutex
count int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock() // 确保解锁
c.count++
// 即使这里 panic,锁也会被释放
}
func (c *SafeCounter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.count
}
// 4. 计时函数
func timeTrack(name string) func() {
start := time.Now()
return func() {
elapsed := time.Since(start)
fmt.Printf("%s 耗时: %v\n", name, elapsed)
}
}
func slowOperation() {
defer timeTrack("slowOperation")() // 注意括号
time.Sleep(100 * time.Millisecond)
}
// 5. 恢复 panic
func safeOperation() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到 panic:", r)
}
}()
panic("something went wrong")
}
// 6. 数据库事务
func transferMoney(db *sql.DB, from, to string, amount float64) error {
tx, err := db.Begin()
if err != nil {
return err
}
// defer 处理提交或回滚
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
// 执行转账逻辑...
return nil
}
// 7. 运维场景:执行状态追踪
func runTask(taskName string) {
fmt.Printf("[%s] 任务开始\n", taskName)
defer fmt.Printf("[%s] 任务结束\n", taskName)
// 执行任务...
time.Sleep(50 * time.Millisecond)
}
func main() {
slowOperation()
safeOperation()
runTask("备份数据库")
runTask("清理日志")
}
4.3 defer 的陷阱
package main
import "fmt"
func main() {
// 陷阱1:defer 参数立即求值
x := 10
defer fmt.Println("defer x =", x) // 输出 10
x = 20
fmt.Println("当前 x =", x) // 输出 20
// 解决:使用闭包
y := 10
defer func() {
fmt.Println("闭包 y =", y) // 输出 20
}()
y = 20
// 陷阱2:循环中的 defer(可能导致资源堆积)
// 错误示例:
// for i := 0; i < 1000; i++ {
// file, _ := os.Open(files[i])
// defer file.Close() // 所有 defer 在函数结束才执行!
// }
// 正确做法:封装到函数中
// for i := 0; i < 1000; i++ {
// processFile(files[i]) // 每个函数结束时关闭文件
// }
// 陷阱3:defer 中修改命名返回值
fmt.Println("result:", deferReturn())
}
func deferReturn() (result int) {
defer func() {
result++ // 可以修改命名返回值
}()
return 10 // 最终返回 11
}
// 对比:匿名返回值
func deferReturnAnonymous() int {
result := 0
defer func() {
result++ // 不会影响返回值
}()
return result // 返回 0
}
五、init 函数
5.1 init 函数特性
package main
import (
"fmt"
"os"
)
// 包级变量(最先初始化)
var config = loadConfig()
func loadConfig() string {
fmt.Println("1. 加载配置")
return "default"
}
// init 函数(可以有多个,按声明顺序执行)
func init() {
fmt.Println("2. init 函数 1")
}
func init() {
fmt.Println("3. init 函数 2")
// 常用于:
// - 初始化包级变量
// - 注册驱动
// - 检查环境
if os.Getenv("DEBUG") != "" {
fmt.Println(" 调试模式已启用")
}
}
func init() {
fmt.Println("4. init 函数 3")
}
func main() {
fmt.Println("5. main 函数")
}
// 输出顺序:
// 1. 加载配置
// 2. init 函数 1
// 3. init 函数 2
// 4. init 函数 3
// 5. main 函数
5.2 init 的典型用途
package main
import (
"database/sql"
"fmt"
"log"
"os"
"regexp"
_ "github.com/go-sql-driver/mysql" // 只执行 init,注册驱动
)
// 编译时正则表达式
var (
emailRegex *regexp.Regexp
ipRegex *regexp.Regexp
)
func init() {
// 初始化正则(编译失败直接 panic)
emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
ipRegex = regexp.MustCompile(`^(\d{1,3}\.){3}\d{1,3}$`)
}
// 环境检查
func init() {
required := []string{"DB_HOST", "DB_USER", "DB_PASS"}
for _, env := range required {
if os.Getenv(env) == "" {
log.Printf("警告: 环境变量 %s 未设置\n", env)
}
}
}
// 注册数据库驱动后可以使用
func connectDB() (*sql.DB, error) {
dsn := fmt.Sprintf("%s:%s@tcp(%s:3306)/mydb",
os.Getenv("DB_USER"),
os.Getenv("DB_PASS"),
os.Getenv("DB_HOST"),
)
return sql.Open("mysql", dsn)
}
func main() {
fmt.Println("邮箱验证:", emailRegex.MatchString("test@example.com"))
fmt.Println("IP 验证:", ipRegex.MatchString("192.168.1.1"))
}
六、匿名函数与立即执行
package main
import (
"fmt"
"sync"
)
func main() {
// 匿名函数赋值给变量
greet := func(name string) string {
return "Hello, " + name
}
fmt.Println(greet("Gopher"))
// 立即执行函数(IIFE)
result := func(a, b int) int {
return a + b
}(10, 20)
fmt.Println("结果:", result)
// 运维场景:并发执行多个检查
var wg sync.WaitGroup
checks := []string{"CPU", "Memory", "Disk", "Network"}
for _, check := range checks {
wg.Add(1)
// 立即执行,传入参数避免闭包问题
go func(checkName string) {
defer wg.Done()
fmt.Printf("检查 %s...\n", checkName)
// 执行实际检查...
}(check)
}
wg.Wait()
// 封装局部作用域
func() {
tempFile := "/tmp/test.txt"
// 使用临时文件
_ = tempFile
// 函数结束,tempFile 不再可见
}()
}
七、递归函数
package main
import (
"fmt"
"os"
"path/filepath"
)
// 阶乘(经典递归)
func factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n-1)
}
// 斐波那契(优化版,避免重复计算)
func fibonacci(n int) int {
memo := make(map[int]int)
var fib func(int) int
fib = func(n int) int {
if n <= 1 {
return n
}
if v, ok := memo[n]; ok {
return v
}
memo[n] = fib(n-1) + fib(n-2)
return memo[n]
}
return fib(n)
}
// 运维场景:递归遍历目录
func walkDir(dir string, depth int) error {
entries, err := os.ReadDir(dir)
if err != nil {
return err
}
indent := ""
for i := 0; i < depth; i++ {
indent += " "
}
for _, entry := range entries {
path := filepath.Join(dir, entry.Name())
if entry.IsDir() {
fmt.Printf("%s[D] %s/\n", indent, entry.Name())
if err := walkDir(path, depth+1); err != nil {
return err
}
} else {
info, _ := entry.Info()
fmt.Printf("%s[F] %s (%d bytes)\n", indent, entry.Name(), info.Size())
}
}
return nil
}
// 运维场景:递归查找进程树
type Process struct {
PID int
Name string
Children []*Process
}
func printProcessTree(p *Process, indent string) {
fmt.Printf("%s[%d] %s\n", indent, p.PID, p.Name)
for _, child := range p.Children {
printProcessTree(child, indent+" ")
}
}
func main() {
fmt.Println("5! =", factorial(5))
fmt.Println("fib(10) =", fibonacci(10))
// 遍历当前目录
fmt.Println("\n目录结构:")
walkDir(".", 0)
// 进程树示例
fmt.Println("\n进程树:")
root := &Process{
PID: 1,
Name: "init",
Children: []*Process{
{
PID: 100,
Name: "nginx",
Children: []*Process{
{PID: 101, Name: "nginx: worker"},
{PID: 102, Name: "nginx: worker"},
},
},
{PID: 200, Name: "sshd"},
},
}
printProcessTree(root, "")
}
八、函数最佳实践
8.1 参数设计
package main
import (
"fmt"
"time"
)
// 使用配置结构体代替多参数
type ServerConfig struct {
Host string
Port int
Timeout time.Duration
MaxRetries int
EnableTLS bool
CertFile string
KeyFile string
}
// 差:参数过多
func startServerBad(host string, port int, timeout time.Duration,
maxRetries int, enableTLS bool, certFile, keyFile string) {
// ...
}
// 好:使用配置结构体
func startServerGood(config ServerConfig) {
fmt.Printf("启动服务器: %s:%d\n", config.Host, config.Port)
}
// 更好:使用函数选项模式
type ServerOption func(*ServerConfig)
func WithTimeout(d time.Duration) ServerOption {
return func(c *ServerConfig) {
c.Timeout = d
}
}
func WithTLS(certFile, keyFile string) ServerOption {
return func(c *ServerConfig) {
c.EnableTLS = true
c.CertFile = certFile
c.KeyFile = keyFile
}
}
func WithMaxRetries(n int) ServerOption {
return func(c *ServerConfig) {
c.MaxRetries = n
}
}
func NewServer(host string, port int, opts ...ServerOption) *ServerConfig {
// 默认配置
config := &ServerConfig{
Host: host,
Port: port,
Timeout: 30 * time.Second,
MaxRetries: 3,
}
// 应用选项
for _, opt := range opts {
opt(config)
}
return config
}
func main() {
// 简单配置
server1 := NewServer("localhost", 8080)
fmt.Printf("服务器1: %+v\n", server1)
// 自定义配置
server2 := NewServer("0.0.0.0", 443,
WithTimeout(60*time.Second),
WithMaxRetries(5),
WithTLS("/etc/ssl/cert.pem", "/etc/ssl/key.pem"),
)
fmt.Printf("服务器2: %+v\n", server2)
}
8.2 错误处理模式
package main
import (
"errors"
"fmt"
)
// 定义错误
var (
ErrNotFound = errors.New("resource not found")
ErrTimeout = errors.New("operation timeout")
)
// 返回错误信息
func findServer(id string) (string, error) {
if id == "" {
return "", fmt.Errorf("invalid server id: %w", ErrNotFound)
}
return "web-01", nil
}
// 多返回值错误处理
func processData(data []byte) (result string, err error) {
// 使用 defer 处理 panic
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic recovered: %v", r)
}
}()
if len(data) == 0 {
return "", errors.New("empty data")
}
return string(data), nil
}
func main() {
// 标准错误处理
server, err := findServer("")
if err != nil {
if errors.Is(err, ErrNotFound) {
fmt.Println("服务器不存在")
} else {
fmt.Println("其他错误:", err)
}
return
}
fmt.Println("找到服务器:", server)
}
九、本章小结
| 主题 | 核心要点 |
|---|---|
| if 语句 | 无括号,支持简短语句声明变量 |
| switch | 默认 break,支持无条件和类型 switch |
| for 循环 | 唯一循环结构,支持 range 遍历 |
| 函数声明 | 多返回值、命名返回值、可变参数 |
| 闭包 | 捕获外部变量,实现状态封装 |
| defer | LIFO 执行,用于资源清理 |
| init | 包初始化,自动执行,常用于注册 |
| 函数选项 | 灵活的参数配置模式 |
运维开发建议
- 善用
defer确保资源释放 - 错误处理要明确,不要忽略错误
- 使用函数选项模式设计灵活的 API
- 避免在循环中使用
defer - Go 1.22+ 循环变量作用域已修复