Go语言的循环语句、判断语句、通道选择语句

小提示

  • Go语言仅支持for循环,但可通过不同写法实现whileforeach功能。

  • 避免无限循环需确保循环条件能终止。

  • 使用breakcontinue控制循环流程。

1.for循环语句

Go 语言只有 for 一种循环结构,支持三种形式:

语法格式如下:

基本 for 循环:

for initialization; condition; post {

// 循环体

}

类似 while 的循环:

for condition {

// 循环体

}

无限循环:

复制代码
for {
    // 循环体(需内部 break 退出)
}

注意事项

  • 循环变量作用域仅在 for 块内
  • 避免在循环中修改迭代变量(如数组遍历时)
  • 无限循环需明确退出条件,防止死循环

示例代码

复制代码
// 基本for循环
for i := 0; i < 5; i++ {
    fmt.Println(i)
}

// while式循环
sum := 1
for sum < 100 {
    sum += sum
}

// 遍历数组
nums := []int{2, 4, 6}
for idx, val := range nums {
    fmt.Printf("index:%d, value:%d\n", idx, val)
}

2.break、continue、goto语句

2.1 break 语句

break 用于立即终止当前所在的 forswitchselect 语句块的执行,并跳出该块继续执行后续代码。

示例代码

复制代码
for i := 0; i < 5; i++ {
    if i == 3 {
        break // 当 i=3 时终止循环
    }
    fmt.Println(i)
}
// 输出: 0 1 2

2.2 continue 语句

continue 用于跳过当前循环的剩余代码,直接进入下一次迭代(仅适用于 for 循环)。

复制代码
for i := 0; i < 5; i++ {
    if i == 2 {
        continue // 跳过 i=2 的打印
    }
    fmt.Println(i)
}
// 输出: 0 1 3 4

2.3 goto 语句

goto 无条件跳转到函数内定义的标签处执行代码。需谨慎使用,可能导致代码可读性降低。

复制代码
func main() {
    i := 0
Loop: // 标签定义
    if i < 3 {
        fmt.Println(i)
        i++
        goto Loop // 跳转回标签
    }
}
// 输出: 0 1 2

提示

  1. breakcontinue 的作用范围

    • 默认仅影响最内层循环,可通过标签扩展作用范围(如 break Label)。
  2. goto 的限制

    • 不能跨函数跳转。
    • 避免跳转到变量初始化之前,否则编译错误。
  3. 标签命名规范

    • 标签名需符合标识符规则,通常使用大写字母开头(如 Exit:)。

3.if语句

if condition {

// 条件为真时执行

} else if condition2 {

// 条件2为真时执行

} else {

// 其他情况执行

}

4.switch语句

Go 语言中的 switch 语句提供了一种多分支选择结构,比 if-else 链更清晰,语法格式如下:

复制代码
switch expression {
case value1:
    // 代码块
case value2:
    // 代码块
default:
    // 默认代码块
}
  • 表达式匹配switch 后可以跟一个表达式(或为空),case 值会与表达式结果比较。
  • 无 fallthrough :默认情况下,case 执行完成后会自动跳出 switch,无需 break
  • 显式 fallthrough :若需继续执行下一个 case,需使用 fallthrough 关键字。
  • 类型匹配case 值必须与 switch 表达式类型兼容。
  • 多值匹配 :单个 case 可以包含多个值,用逗号分隔。

提示

  • 省略表达式 :若 switch 后无表达式,等同于 switch true,适合替代长 if-else 链。
  • 默认顺序default 分支可放在任意位置,但通常置于末尾。
  • 作用域限制switch 内声明的变量仅在其块内有效。
  • 类型推断case 值可以是常量、变量或表达式,但需与 switch 表达式类型一致。

示例代码:

基础用法

复制代码
day := 3
switch day {
case 1:
    fmt.Println("Monday")
case 2:
    fmt.Println("Tuesday")
case 3:
    fmt.Println("Wednesday")
default:
    fmt.Println("Invalid day")
}

无表达式(布尔匹配)

复制代码
score := 85
switch {
case score >= 90:
    fmt.Println("A")
case score >= 80:
    fmt.Println("B")
default:
    fmt.Println("C")
}

多值匹配

复制代码
month := "April"
switch month {
case "January", "February", "March":
    fmt.Println("Winter")
case "April", "May", "June":
    fmt.Println("Spring")
default:
    fmt.Println("Other season")
}

使用 fallthrough

复制代码
num := 1
switch num {
case 1:
    fmt.Println("One")
    fallthrough
case 2:
    fmt.Println("Two")
default:
    fmt.Println("Default")
}
// 输出: One Two

类型匹配

复制代码
var x interface{} = 10
switch x.(type) {
case int:
    fmt.Println("Integer")
case string:
    fmt.Println("String")
default:
    fmt.Println("Unknown type")
}

5.select 语句

select 用于监听多个 channel 的读写操作,类似于 switch 但专为 channel 设计。它会阻塞直到某个 case 就绪,随机选择一个执行(当多个 case 就绪时)。没有 default 子句时,select 会一直阻塞。语法如下:

复制代码
select {
case <-channel1:
    // 当 channel1 可读时执行
case data := <-channel2:
    // 当 channel2 可读时执行,并接收数据到 data
case channel3 <- value:
    // 当 channel3 可写时执行
default:
    // 当没有任何 channel 就绪时执行
}

提示

  • 空的 select 语句(select{})会永久阻塞,可用于阻止 main 函数退出
  • 当所有 case 都不满足且无 default 时,select 会阻塞
  • 多个 case 就绪时,执行哪个是随机的
  • default 可实现非阻塞的 channel 操作
  • 常用于超时控制和多路复用

示例代码

基本用法
复制代码
ch1 := make(chan string)
ch2 := make(chan string)

go func() {
    time.Sleep(1 * time.Second)
    ch1 <- "from ch1"
}()

go func() {
    time.Sleep(2 * time.Second)
    ch2 <- "from ch2"
}()

select {
case msg := <-ch1:
    fmt.Println(msg)
case msg := <-ch2:
    fmt.Println(msg)
}
非阻塞读取
复制代码
select {
case msg := <-channel:
    fmt.Println("received:", msg)
default:
    fmt.Println("no message received")
}
超时控制
复制代码
select {
case res := <-doSomething():
    fmt.Println(res)
case <-time.After(3 * time.Second):
    fmt.Println("timeout")
}
永久监听
复制代码
for {
    select {
    case msg := <-msgChannel:
        process(msg)
    case <-quitChannel:
        return
    }
}
多channel合并
复制代码
func merge(cs ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup
    
    for _, c := range cs {
        wg.Add(1)
        go func(c <-chan int) {
            for v := range c {
                out <- v
            }
            wg.Done()
        }(c)
    }
    
    go func() {
        wg.Wait()
        close(out)
    }()
    
    return out
}

总结

Go 语言仅提供for一种循环语句,却能实现多种循环模式,包括基本循环、类 while 循环和无限循环,配合range还可便捷遍历数组、切片等数据结构。使用时需注意循环变量作用域,避免在循环中修改迭代变量,无限循环必须设置明确退出条件,防止出现死循环。

跳转语句中,break用于终止当前循环或分支语句,continue仅跳过本次循环剩余代码,二者均可配合标签实现对多层循环的控制。goto可实现无条件跳转,但会降低代码可读性,应谨慎使用,且不能跨函数跳转或跳过变量初始化。

分支语句方面,if语句简洁直观,支持条件判断与简短语句声明。switch语句功能强大,支持表达式匹配、多值匹配、无表达式判断及类型判断,默认执行完一个 case 后自动退出,如需继续执行下一个 case 需显式使用fallthrough,相比多层if-else结构更清晰高效。

select是 Go 语言专为通道设计的多路复用语句,用于监听多个通道的读写操作,会阻塞至某个 case 就绪,多个 case 就绪时随机选择执行。无 case 就绪且存在default时执行默认分支,无default则持续阻塞。它常用于通道非阻塞操作、超时控制、协程通信等场景,是实现并发控制的重要工具。

合理运用循环、分支、跳转与 select 语句,能让程序逻辑更清晰、并发更高效。

相关推荐
551只玄猫5 小时前
【数学建模 matlab 实验报告12】聚类分析和判别分析
开发语言·数学建模·matlab·课程设计·聚类·实验报告
小陈工7 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
海清河晏1117 小时前
数据结构 | 单循环链表
数据结构·算法·链表
H Journey7 小时前
C++之 CMake、CMakeLists.txt、Makefile
开发语言·c++·makefile·cmake
呆萌很10 小时前
【GO】结构体构造函数练习题
golang
wuweijianlove11 小时前
算法性能的渐近与非渐近行为对比的技术4
算法
_dindong11 小时前
cf1091div2 C.Grid Covering(数论)
c++·算法
AI成长日志11 小时前
【Agentic RL】1.1 什么是Agentic RL:从传统RL到智能体学习
人工智能·学习·算法
lly20240612 小时前
C 标准库 - `<stdio.h>`
开发语言