4. Go 基础语法速览:变量与常量、基本数据类型、控制结构、函数与错误处理
在开始构建 Web 服务之前,掌握 Go 的核心语法是高效开发的基础。本章将快速梳理变量与常量、基本数据类型、三大控制结构(if、for、switch)以及函数与错误处理机制。这些知识点将贯穿整个课程,是编写可靠、可维护 Go 代码的基石。
4.1 变量与常量
Go 语言是静态类型语言,变量声明后类型不可变。Go 提供了多种声明方式以适应不同场景,同时通过 const 关键字支持编译时常量。
4.1.1 变量声明
| 声明方式 | 语法示例 | 适用场景 |
|---|---|---|
| 标准声明 | var name string = "Go" |
需要显式指定类型或初始化值 |
| 类型推断 | var port = 8080 |
编译器根据初始值自动推导类型 |
| 短变量声明 | msg := "Hello" |
函数内部声明并初始化,最常用 |
| 批量声明 | var ( x int; y string ) |
声明多个相关变量,提高可读性 |
💡 关键点: 短变量声明
:= 只能在函数内部使用;包级别变量必须使用 var 关键字。未使用的局部变量会导致编译错误。
4.1.2 常量与 iota
常量使用 const 声明,值在编译期确定。Go 提供了 iota 枚举生成器,用于创建一组递增的常量。
const (
StatusOK = 200
StatusNotFound = 404
)
// iota 示例:定义日志级别
const (
DebugLevel = iota // 0
InfoLevel // 1
WarnLevel // 2
ErrorLevel // 3
)
💡 提示:
iota 在每次出现 const 关键字时重置为 0,常用于枚举、位掩码或状态码定义。
4.2 基本数据类型
Go 的基本数据类型分为四大类:布尔型、数值型、字符串型和派生类型。下表列出了 Web 开发中最常用的类型。
| 类别 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| 布尔 | bool |
true 或 false |
false |
| 整型 | int, int8 ~ int64 |
平台相关(32/64位)或定长 | 0 |
| 无符号整型 | uint, uint8 ~ uint64 |
非负整数,常用于位运算 | 0 |
| 浮点型 | float32, float64 |
Web 开发中优先使用 float64 |
0.0 |
| 字符串 | string |
UTF-8 编码,不可变字节序列 | "" |
| 字节 | byte |
uint8 的别名,处理原始数据 |
0 |
| 符文 | rune |
int32 的别名,表示 Unicode 码点 |
0 |
⚠️ 注意: Go 没有隐式类型转换。不同数值类型之间必须显式转换,例如
int64(port)。字符串与数值之间需使用 strconv 包。
4.3 控制结构:if、for、switch
Go 的控制结构简洁且无括号包裹条件,所有控制语句都支持在条件前执行一个简单语句(如变量声明)。
4.3.1 if 语句
// 标准 if-else
if statusCode >= 400 {
log.Println("请求失败")
} else if statusCode >= 300 {
log.Println("重定向")
} else {
log.Println("成功")
}
// 带初始化语句的 if(作用域仅限于 if 块)
if err := validateRequest(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
4.3.2 for 循环
Go 只有 for 关键字,但能实现所有循环模式。
| 模式 | 语法 | 示例 |
|---|---|---|
| 标准 for | for init; condition; post { } |
for i := 0; i < 10; i++ { } |
| 条件 for(类似 while) | for condition { } |
for retries > 0 { } |
| 无限循环 | for { } |
for { select {} } 用于常驻服务 |
| range 遍历 | for index, value := range collection { } |
遍历切片、map、字符串、通道 |
// range 遍历 HTTP 请求头
for key, values := range r.Header {
for _, v := range values {
log.Printf("Header %s: %s", key, v)
}
}
4.3.3 switch 语句
Go 的 switch 默认每个 case 后自动 break,无需显式写 break。支持表达式、类型判断和 fallthrough。
// 表达式 switch
switch method := r.Method; method {
case http.MethodGet:
handleGet(w, r)
case http.MethodPost:
handlePost(w, r)
case http.MethodPut, http.MethodPatch:
handleUpdate(w, r)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
// 类型 switch(用于接口类型断言)
var data interface{} = "hello"
switch v := data.(type) {
case string:
fmt.Println("字符串长度:", len(v))
case int:
fmt.Println("整数值:", v)
default:
fmt.Println("未知类型")
}
💡 提示: 在 Web 路由处理中,
switch 比 if-else 链更清晰。类型 switch 是处理多类型接口值的标准方式。
4.4 函数与错误处理
Go 函数支持多返回值,这是其错误处理机制的核心。函数是一等公民,可以作为参数传递或作为返回值返回。
4.4.1 函数定义
// 标准函数:多返回值
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为0")
}
return a / b, nil
}
// 命名返回值(在函数体内直接赋值,return 时自动返回)
func parseConfig(path string) (cfg *Config, err error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
cfg = &Config{}
err = json.Unmarshal(data, cfg)
return
}
// 可变参数
func logRequest(method string, headers ...string) {
fmt.Printf("Method: %s\n", method)
for _, h := range headers {
fmt.Printf("Header: %s\n", h)
}
}
4.4.2 错误处理惯用法
Go 没有异常机制,错误通过返回值传递。调用者必须显式检查错误,这是 Go 代码健壮性的来源。
| 模式 | 代码示例 | 说明 |
|---|---|---|
| 基本检查 | if err != nil { return err } |
最常用,立即返回错误 |
| 错误包装 | fmt.Errorf("上下文: %w", err) |
使用 %w 保留原始错误链 |
| defer + recover | defer func() { if r := recover(); r != nil { } }() |
捕获 panic,仅用于不可恢复场景 |
| 自定义错误 | type MyError struct { Code int; Msg string } |
实现 Error() string 接口 |
// Web 服务中的典型错误处理模式
func handler(w http.ResponseWriter, r *http.Request) {
user, err := getUserFromDB(r.Context(), r.URL.Query().Get("id"))
if err != nil {
// 包装错误并返回 HTTP 500
log.Printf("获取用户失败: %v", err)
http.Error(w, "内部服务器错误", http.StatusInternalServerError)
return
}
// 正常处理
json.NewEncoder(w).Encode(user)
}
⚠️ 注意: 永远不要忽略错误。如果函数返回 error,调用者必须处理它。使用
_ 忽略错误仅适用于明确知道不会出错的情况(如 fmt.Fprint 写入 bytes.Buffer)。
4.5 综合示例:Web 处理函数中的语法应用
以下示例将本章所有语法点融合到一个简单的 HTTP 处理函数中,展示实际开发中的写法。
package main
import (
"encoding/json"
"errors"
"log"
"net/http"
"strconv"
)
// User 结构体(后续章节详解)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
// 模拟数据库查询
func findUserByID(id int) (*User, error) {
if id <= 0 {
return nil, errors.New("无效的用户ID")
}
// 模拟数据
return &User{ID: id, Name: "Alice"}, nil
}
// getUserHandler 是典型的 Web 处理函数
func getUserHandler(w http.ResponseWriter, r *http.Request) {
// 1. 解析查询参数
idStr := r.URL.Query().Get("id")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "参数 id 必须是整数", http.StatusBadRequest)
return
}
// 2. 调用业务逻辑
user, err := findUserByID(id)
if err != nil {
log.Printf("查询用户失败: %v", err)
http.Error(w, "用户未找到", http.StatusNotFound)
return
}
// 3. 设置响应头并返回 JSON
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(user)
}
func main() {
http.HandleFunc("/user", getUserHandler)
log.Println("服务启动在 :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
💡 提示: 上述代码展示了变量声明(
:=)、基本类型转换(strconv.Atoi)、if 错误检查、函数多返回值、常量状态码(http.StatusBadRequest)等核心语法。这是 Go Web 开发的标准模式。