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 语句,能让程序逻辑更清晰、并发更高效。

相关推荐
weixin_5231853220 小时前
SimpleDateFormat为什么线程不安全?源码级解析与解决方案
java·开发语言·安全
神仙别闹20 小时前
基于C语言处理机调度算法的实现
服务器·c语言·算法
Brilliantwxx20 小时前
【算法从零到千】【16-23】 二分算法
数据结构·算法
Chase_______20 小时前
【Java杂项】Java 中的 null:空指针、自动拆箱与集合边界详解
java·开发语言
j7~20 小时前
【C++】STL--string类--拆析解剖string以及string类的底层详解(1)
开发语言·c++·ascii编码·string类·auto和范围for
techdashen20 小时前
Rust 项目管理动态 — 2026 年 2 月
开发语言·后端·rust
8Qi81 天前
回文子串(Palindromic Substrings)—— 题解
算法·leetcode·职场和发展·动态规划
想吃火锅10051 天前
【leetcode】405.数字转换为十六进制数js
开发语言·javascript·ecmascript
专注VB编程开发20年1 天前
AI 生成C# WinForm 窗体 = 目前就是垃圾
开发语言·人工智能·c#
cfm_29141 天前
JVM GC垃圾回收初步了解
java·开发语言·jvm