3. Go 语言基础回顾(上):变量与常量、基本数据类型、流程控制、函数定义与多返回值

在正式进入任务调度平台 OpenAPI 服务的开发之前,我们需要快速回顾 Go 语言的核心基础语法。本章聚焦于变量与常量、基本数据类型、流程控制以及函数定义,这些是构建后续所有 API 端点、中间件和业务逻辑的基石。

3.1 变量与常量

Go 语言是静态类型语言,但提供了类型推断机制,使得声明变量非常灵活。常量则使用 const 关键字定义,支持枚举和隐式重复(iota)。

3.1.1 变量声明方式

声明方式 语法示例 适用场景
标准声明 var name string = "scheduler" 需要显式指定类型或包级变量
类型推断 var port = 8080 局部变量,编译器可推导类型
短变量声明 count := 100 函数内部最常用,简洁高效
批量声明 var ( x int; y string ) 包级变量分组,提升可读性
💡 避坑提示: 短变量声明 := 不能用于函数外部;且左侧必须至少有一个新变量,否则编译报错。

3.1.2 常量与 iota 枚举

常量使用 const 声明,编译期确定值。结合 iota 可以实现自增枚举,常用于定义任务状态码或错误码。

const (
    StatusPending = iota // 0
    StatusRunning        // 1
    StatusCompleted      // 2
    StatusFailed         // 3
)
📌 最佳实践: 在 OpenAPI 服务中,建议将常量集中定义在 constant 包中,避免魔法数字散落在业务代码里。
变量与常量声明流程对比 变量声明 var / := 运行时赋值 可被修改 常量声明 const / iota 编译期确定 不可修改 变量 vs 常量 运行时可变 vs 编译期固定

3.2 基本数据类型

Go 语言内置了丰富的基本数据类型,是定义 API 请求/响应结构体的基础。下表列出了最常用的类型及其默认值:

类别 类型 默认值 说明
布尔 bool false 条件判断、开关标志
整数 int, int8 ~ int64 0 平台相关位数(32/64位)
无符号整数 uint, uint8 ~ uint64 0 非负数值,如 ID、计数
浮点数 float32, float64 0.0 API 中推荐使用 float64
字符串 string ""(空字符串) UTF-8 编码,不可变字节序列
字节 byte(uint8 别名) 0 处理原始二进制数据
符文 rune(int32 别名) 0 Unicode 码点,处理多语言字符
⚠️ 类型转换注意: Go 没有隐式类型转换。例如 int 转 int64 必须显式写 int64(port),否则编译失败。

3.3 流程控制:if / for / switch

Go 语言的流程控制语法简洁,没有括号包裹条件,且 for 是唯一的循环关键字。

3.3.1 if 语句

支持在条件前执行一个简单语句,常用于错误处理:

if err := validateTask(task); err != nil {
    return nil, err
}

3.3.2 for 循环

Go 只有 for,但可以模拟 while 和无限循环:

// 标准 for 循环
for i := 0; i < len(tasks); i++ {
    fmt.Println(tasks[i].Name)
}

// 类似 while
for len(queue) > 0 {
    process(queue[0])
    queue = queue[1:]
}

// 无限循环(常用于服务监听)
for {
    select {
    case req <- requestCh:
        handle(req)
    }
}

3.4.3 switch 语句

Go 的 switch 默认不穿透(无需 break),且支持表达式和类型判断:

switch status {
case StatusPending:
    return "pending"
case StatusRunning:
    return "running"
default:
    return "unknown"
}
💡 实用技巧: 在 OpenAPI 路由处理中,常用 switch 匹配 HTTP 方法(GET/POST/PUT/DELETE),代码比 if-else 链更清晰。
Go 流程控制结构 if / else if / else 条件为 true 时执行 支持前置简单语句 for(唯一循环) for ; ; {} 无限循环 for range 遍历集合 switch / select 默认不穿透 支持类型断言 三种控制流覆盖所有业务逻辑场景

3.4 函数定义与多返回值

函数是 Go 代码复用的基本单元。Go 函数支持多返回值,这是其最鲜明的特性之一,在 OpenAPI 服务中广泛用于返回结果和错误。

3.4.1 函数声明语法

func 函数名(参数列表) (返回值列表) {
    // 函数体
}

3.4.2 多返回值示例

以下是一个典型的任务查询函数,同时返回任务对象和错误:

func GetTaskByID(id int64) (*Task, error) {
    if id <= 0 {
        return nil, fmt.Errorf("invalid task id: %d", id)
    }
    task, ok := cache[id]
    if !ok {
        return nil, ErrTaskNotFound
    }
    return task, nil
}

3.4.3 命名返回值

Go 支持为返回值命名,在函数体内视为变量,return 时可省略操作数:

func SplitTaskName(name string) (prefix, suffix string) {
    parts := strings.SplitN(name, "_", 2)
    if len(parts) == 2 {
        prefix = parts[0]
        suffix = parts[1]
    } else {
        prefix = name
        suffix = ""
    }
    return // 自动返回 prefix, suffix
}
✅ 推荐用法: 在 OpenAPI handler 中,统一使用 (*Response, error) 作为返回值模式,便于中间件统一处理错误响应。

3.4.4 函数作为参数与闭包

Go 函数是一等公民,可以作为参数传递或作为返回值返回。这在实现中间件链时非常关键:

// 中间件模式
type Middleware func(Handler) Handler

func LoggerMiddleware(next Handler) Handler {
    return func(ctx context.Context, req *Request) (*Response, error) {
        log.Printf("request: %v", req)
        return next(ctx, req)
    }
}
📌 进阶提示: 闭包捕获外部变量时注意引用语义,在循环中创建 goroutine 时建议显式复制循环变量,避免数据竞争。