Go语言控制结构
本文档详细介绍Go语言的控制结构,包括条件语句、循环语句和跳转语句等流程控制机制。
📋 目录
控制结构概述
Go语言提供了三种基本的控制结构:
- 顺序控制 - 程序按顺序执行
- 分支控制 - 根据条件选择执行路径
- 循环控制 - 重复执行代码块
程序执行流程
go
package main
import "fmt"
func main() {
// 1. 顺序执行
fmt.Println("步骤1")
fmt.Println("步骤2")
// 2. 分支控制
x := 10
if x > 5 {
fmt.Println("x大于5")
}
// 3. 循环控制
for i := 0; i < 3; i++ {
fmt.Printf("循环第%d次\n", i+1)
}
}条件语句
if 语句
基本语法
go
// 基本if语句
if condition {
// 条件为true时执行
}
// if-else语句
if condition {
// 条件为true时执行
} else {
// 条件为false时执行
}
// if-else if-else语句
if condition1 {
// condition1为true时执行
} else if condition2 {
// condition2为true时执行
} else {
// 所有条件都为false时执行
}实际示例
go
func main() {
age := 18
// 简单if语句
if age >= 18 {
fmt.Println("已成年")
}
// if-else语句
if age >= 60 {
fmt.Println("老年人")
} else if age >= 18 {
fmt.Println("成年人")
} else {
fmt.Println("未成年人")
}
// 多条件判断
score := 85
if score >= 90 {
fmt.Println("优秀")
} else if score >= 80 {
fmt.Println("良好")
} else if score >= 70 {
fmt.Println("中等")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
}if语句的特殊用法
1. 带初始化语句的if
go
// 在if语句中声明变量
if num := 42; num > 0 {
fmt.Printf("正数: %d\n", num)
}
// num在此处不可访问
// 实际应用:错误处理
if err := someFunction(); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
// 文件操作示例
if file, err := os.Open("test.txt"); err != nil {
fmt.Printf("打开文件失败: %v\n", err)
} else {
defer file.Close()
fmt.Println("文件打开成功")
}2. 逻辑运算符
go
func main() {
age := 25
hasLicense := true
// 逻辑与 (&&)
if age >= 18 && hasLicense {
fmt.Println("可以开车")
}
// 逻辑或 (||)
if age < 18 || !hasLicense {
fmt.Println("不能开车")
}
// 逻辑非 (!)
if !hasLicense {
fmt.Println("没有驾照")
}
// 复杂条件
income := 50000
if (age >= 18 && age <= 65) && (income > 30000 || hasLicense) {
fmt.Println("符合贷款条件")
}
}3. 短路求值
go
func expensiveOperation() bool {
fmt.Println("执行昂贵操作")
return true
}
func main() {
x := 5
// 短路与:如果第一个条件为false,不会执行第二个条件
if x > 10 && expensiveOperation() {
fmt.Println("条件成立")
}
// expensiveOperation不会被调用
// 短路或:如果第一个条件为true,不会执行第二个条件
if x > 0 || expensiveOperation() {
fmt.Println("条件成立")
}
// expensiveOperation不会被调用
}循环语句
Go语言只有一种循环语句:for,但它有多种形式。
for 循环的形式
1. 标准for循环
go
// 基本语法
for 初始化; 条件; 后置语句 {
// 循环体
}
// 示例
func main() {
// 基本循环
for i := 0; i < 5; i++ {
fmt.Printf("i = %d\n", i)
}
// 嵌套循环
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
fmt.Printf("(%d,%d) ", i, j)
}
fmt.Println()
}
}2. while风格循环
go
func main() {
// 省略初始化和后置语句
i := 0
for i < 5 {
fmt.Printf("i = %d\n", i)
i++
}
// 无限循环
count := 0
for {
fmt.Printf("无限循环 %d\n", count)
count++
if count >= 3 {
break // 跳出循环
}
}
}3. range循环
range 用于遍历数组、切片、字符串、映射和通道:
遍历数组和切片
go
func main() {
// 遍历数组
arr := [5]int{10, 20, 30, 40, 50}
// 获取索引和值
for index, value := range arr {
fmt.Printf("arr[%d] = %d\n", index, value)
}
// 只获取索引
for index := range arr {
fmt.Printf("索引: %d\n", index)
}
// 只获取值
for _, value := range arr {
fmt.Printf("值: %d\n", value)
}
// 遍历切片
slice := []string{"Go", "Python", "Java"}
for i, lang := range slice {
fmt.Printf("%d: %s\n", i, lang)
}
}遍历字符串
go
func main() {
str := "Hello世界"
// 按字节遍历
fmt.Println("按字节遍历:")
for i := 0; i < len(str); i++ {
fmt.Printf("%d: %c\n", i, str[i])
}
// 按Unicode字符遍历
fmt.Println("按Unicode字符遍历:")
for index, char := range str {
fmt.Printf("%d: %c\n", index, char)
}
}遍历映射
go
func main() {
m := map[string]int{
"apple": 5,
"banana": 3,
"orange": 8,
}
// 遍历键值对
for key, value := range m {
fmt.Printf("%s: %d\n", key, value)
}
// 只遍历键
for key := range m {
fmt.Printf("键: %s\n", key)
}
// 只遍历值
for _, value := range m {
fmt.Printf("值: %d\n", value)
}
}遍历通道
go
func main() {
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
// 遍历通道中的值
for value := range ch {
fmt.Printf("接收到: %d\n", value)
}
}循环控制语句
break 语句
go
func main() {
// 跳出单层循环
for i := 0; i < 10; i++ {
if i == 5 {
break // 跳出循环
}
fmt.Printf("i = %d\n", i)
}
// 跳出嵌套循环 - 使用标签
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break outer // 跳出外层循环
}
fmt.Printf("(%d,%d) ", i, j)
}
}
fmt.Println("\n循环结束")
}continue 语句
go
func main() {
// 跳过当前迭代
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // 跳过偶数
}
fmt.Printf("奇数: %d\n", i)
}
// 嵌套循环中的continue
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 1 {
continue outer // 跳到外层循环的下一次迭代
}
fmt.Printf("(%d,%d) ", i, j)
}
}
}选择语句
switch 语句
基本switch
go
func main() {
day := 3
switch day {
case 1:
fmt.Println("星期一")
case 2:
fmt.Println("星期二")
case 3:
fmt.Println("星期三")
case 4:
fmt.Println("星期四")
case 5:
fmt.Println("星期五")
case 6, 7: // 多个值
fmt.Println("周末")
default:
fmt.Println("无效的日期")
}
}表达式switch
go
func main() {
score := 85
switch {
case score >= 90:
fmt.Println("优秀")
case score >= 80:
fmt.Println("良好")
case score >= 70:
fmt.Println("中等")
case score >= 60:
fmt.Println("及格")
default:
fmt.Println("不及格")
}
}带初始化的switch
go
func main() {
switch hour := time.Now().Hour(); {
case hour < 6:
fmt.Println("凌晨")
case hour < 12:
fmt.Println("上午")
case hour < 18:
fmt.Println("下午")
default:
fmt.Println("晚上")
}
}fallthrough 语句
go
func main() {
grade := 'B'
switch grade {
case 'A':
fmt.Println("优秀")
fallthrough // 继续执行下一个case
case 'B':
fmt.Println("良好")
fallthrough
case 'C':
fmt.Println("及格")
case 'D':
fmt.Println("不及格")
default:
fmt.Println("无效等级")
}
}类型switch
go
func processValue(value interface{}) {
switch v := value.(type) {
case int:
fmt.Printf("整数: %d\n", v)
case string:
fmt.Printf("字符串: %s\n", v)
case bool:
fmt.Printf("布尔值: %t\n", v)
case []int:
fmt.Printf("整数切片: %v\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
}
func main() {
processValue(42)
processValue("Hello")
processValue(true)
processValue([]int{1, 2, 3})
processValue(3.14)
}select 语句
select 用于处理多个通道操作:
go
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch1 <- "来自ch1的消息"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "来自ch2的消息"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("接收到:", msg1)
case msg2 := <-ch2:
fmt.Println("接收到:", msg2)
case <-time.After(3 * time.Second):
fmt.Println("超时")
return
}
}
}跳转语句
goto 语句
虽然Go支持goto,但不推荐使用:
go
func main() {
i := 0
start:
if i < 5 {
fmt.Printf("i = %d\n", i)
i++
goto start
}
fmt.Println("循环结束")
}标签的使用
标签主要用于break和continue:
go
func main() {
// 查找二维数组中的特定值
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
target := 5
found := false
search:
for i := 0; i < len(matrix); i++ {
for j := 0; j < len(matrix[i]); j++ {
if matrix[i][j] == target {
fmt.Printf("找到 %d 在位置 (%d, %d)\n", target, i, j)
found = true
break search // 跳出所有循环
}
}
}
if !found {
fmt.Printf("未找到 %d\n", target)
}
}错误处理
基本错误处理模式
go
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为0")
}
return a / b, nil
}
func main() {
// 标准错误处理
result, err := divide(10, 2)
if err != nil {
fmt.Printf("错误: %v\n", err)
return
}
fmt.Printf("结果: %.2f\n", result)
// 处理错误情况
result, err = divide(10, 0)
if err != nil {
fmt.Printf("错误: %v\n", err)
// 可以选择返回、继续或其他处理方式
}
}多重错误处理
go
func processFile(filename string) error {
// 打开文件
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("打开文件失败: %w", err)
}
defer file.Close()
// 读取文件
data := make([]byte, 1024)
n, err := file.Read(data)
if err != nil && err != io.EOF {
return fmt.Errorf("读取文件失败: %w", err)
}
// 处理数据
fmt.Printf("读取了 %d 字节\n", n)
return nil
}
func main() {
if err := processFile("test.txt"); err != nil {
fmt.Printf("处理文件时出错: %v\n", err)
}
}错误处理最佳实践
1. 及早返回
go
func validateUser(user User) error {
if user.Name == "" {
return errors.New("用户名不能为空")
}
if user.Age < 0 {
return errors.New("年龄不能为负数")
}
if user.Email == "" {
return errors.New("邮箱不能为空")
}
// 所有验证通过
return nil
}2. 错误包装
go
func readConfig(filename string) (*Config, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("读取配置文件 %s 失败: %w", filename, err)
}
var config Config
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("解析配置文件 %s 失败: %w", filename, err)
}
return &config, nil
}3. 自定义错误类型
go
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("验证失败 - %s: %s", e.Field, e.Message)
}
func validateAge(age int) error {
if age < 0 {
return ValidationError{
Field: "age",
Message: "年龄不能为负数",
}
}
if age > 150 {
return ValidationError{
Field: "age",
Message: "年龄不能超过150",
}
}
return nil
}实际应用示例
go
func main() {
// 用户输入处理
var input string
fmt.Print("请输入一个数字: ")
fmt.Scanln(&input)
// 转换并验证输入
num, err := strconv.Atoi(input)
if err != nil {
fmt.Printf("输入无效: %v\n", err)
return
}
// 根据数字范围进行不同处理
switch {
case num < 0:
fmt.Println("负数")
case num == 0:
fmt.Println("零")
case num > 0 && num <= 10:
fmt.Println("小正数")
case num > 10 && num <= 100:
fmt.Println("中等正数")
default:
fmt.Println("大正数")
}
// 计算阶乘
if num >= 0 && num <= 20 {
factorial := 1
for i := 1; i <= num; i++ {
factorial *= i
}
fmt.Printf("%d的阶乘是: %d\n", num, factorial)
} else if num > 20 {
fmt.Println("数字太大,无法计算阶乘")
}
}通过掌握这些控制结构,您就可以编写具有复杂逻辑的Go程序了。控制结构是编程的基础,合理使用它们可以让程序逻辑清晰、易于维护。