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 包中,避免魔法数字散落在业务代码里。
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 链更清晰。
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 时建议显式复制循环变量,避免数据竞争。