循环语句 #
一、for循环概述 #
Go只有一种循环关键字for,但支持多种形式。
二、标准for循环 #
2.1 基本语法 #
go
for 初始化; 条件; 后置语句 {
// 循环体
}
2.2 示例 #
go
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// 输出: 0 1 2 3 4
2.3 省略部分 #
省略初始化:
go
i := 0
for ; i < 5; i++ {
fmt.Println(i)
}
省略后置语句:
go
for i := 0; i < 5; {
fmt.Println(i)
i++
}
省略条件和后置(相当于while):
go
i := 0
for i < 5 {
fmt.Println(i)
i++
}
三、while风格循环 #
Go没有while关键字,使用for模拟:
go
// 相当于 while(condition)
i := 0
for i < 5 {
fmt.Println(i)
i++
}
// 相当于 while(true)
for {
// 无限循环
if someCondition {
break
}
}
四、死循环 #
4.1 基本形式 #
go
for {
fmt.Println("无限循环")
}
4.2 带退出条件 #
go
for {
result := doSomething()
if result == "done" {
break
}
}
五、for-range循环 #
5.1 遍历切片/数组 #
go
numbers := []int{1, 2, 3, 4, 5}
for index, value := range numbers {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}
省略索引:
go
for _, value := range numbers {
fmt.Println(value)
}
省略值:
go
for index := range numbers {
fmt.Println(index)
}
5.2 遍历映射 #
go
scores := map[string]int{
"Alice": 90,
"Bob": 85,
"Carol": 95,
}
for name, score := range scores {
fmt.Printf("%s: %d\n", name, score)
}
5.3 遍历字符串 #
go
s := "世界"
// 按字节遍历
for i := 0; i < len(s); i++ {
fmt.Printf("%d: %x\n", i, s[i])
}
// 按rune遍历
for i, r := range s {
fmt.Printf("%d: %c\n", i, r)
}
5.4 遍历通道 #
go
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for v := range ch {
fmt.Println(v)
}
六、嵌套循环 #
go
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d*%d=%d\t", j, i, i*j)
}
fmt.Println()
}
七、循环控制 #
7.1 break #
跳出当前循环:
go
for i := 0; i < 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
// 输出: 0 1 2 3 4
7.2 continue #
跳过本次迭代:
go
for i := 0; i < 5; i++ {
if i == 2 {
continue
}
fmt.Println(i)
}
// 输出: 0 1 3 4
7.3 标签 #
用于跳出嵌套循环:
go
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)
}
}
// 输出: (0, 0) (0, 1) (0, 2) (1, 0)
continue使用标签:
go
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 1 {
continue outer
}
fmt.Printf("(%d, %d) ", i, j)
}
}
// 输出: (0, 0) (1, 0) (2, 0)
八、实际应用 #
8.1 求和 #
go
sum := 0
for i := 1; i <= 100; i++ {
sum += i
}
fmt.Println(sum) // 5050
8.2 查找元素 #
go
func find(numbers []int, target int) int {
for i, n := range numbers {
if n == target {
return i
}
}
return -1
}
8.3 过滤 #
go
func filter(numbers []int, condition func(int) bool) []int {
var result []int
for _, n := range numbers {
if condition(n) {
result = append(result, n)
}
}
return result
}
evens := filter([]int{1, 2, 3, 4, 5}, func(n int) bool {
return n%2 == 0
})
fmt.Println(evens) // [2 4]
8.4 重试机制 #
go
func retry(fn func() error, maxAttempts int) error {
for i := 0; i < maxAttempts; i++ {
if err := fn(); err == nil {
return nil
}
time.Sleep(time.Second)
}
return errors.New("max attempts reached")
}
8.5 批量处理 #
go
func batchProcess(items []string, batchSize int, process func([]string)) {
for i := 0; i < len(items); i += batchSize {
end := i + batchSize
if end > len(items) {
end = len(items)
}
process(items[i:end])
}
}
九、常见错误 #
9.1 循环变量作用域 #
go
var funcs []func()
for i := 0; i < 3; i++ {
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for _, f := range funcs {
f()
}
// 输出: 3 3 3(不是 0 1 2)
// 解决方法
for i := 0; i < 3; i++ {
i := i // 创建新变量
funcs = append(funcs, func() {
fmt.Println(i)
})
}
9.2 range值是副本 #
go
type Person struct {
Name string
Age int
}
people := []Person{
{"Alice", 25},
{"Bob", 30},
}
for _, p := range people {
p.Age = 0 // 修改的是副本
}
fmt.Println(people) // Age未改变
// 正确做法
for i := range people {
people[i].Age = 0
}
9.3 无限循环 #
go
i := 0
for i < 5 {
fmt.Println(i)
// 忘记i++,导致无限循环
}
十、最佳实践 #
10.1 选择合适的循环形式 #
go
// 已知次数:标准for
for i := 0; i < n; i++ {}
// 遍历集合:for-range
for _, v := range slice {}
// 条件循环:省略初始化和后置
for condition {}
10.2 避免在循环中创建闭包 #
go
// 不好
for _, item := range items {
go func() {
process(item) // 可能使用最后一个item
}()
}
// 好
for _, item := range items {
item := item
go func() {
process(item)
}()
}
10.3 使用标签提高可读性 #
go
found:
for _, row := range matrix {
for _, cell := range row {
if cell == target {
break found
}
}
}
十一、总结 #
for循环要点:
| 形式 | 说明 |
|---|---|
for init; cond; post {} |
标准for循环 |
for cond {} |
while风格 |
for {} |
死循环 |
for k, v := range coll {} |
range遍历 |
关键点:
- 唯一循环关键字:Go只有for
- 灵活形式:支持多种循环形式
- for-range:遍历数组、切片、映射、通道、字符串
- 标签:break/continue可以配合标签使用
- 变量作用域:注意循环变量在闭包中的问题
准备好学习循环控制了吗?让我们进入下一章!
最后更新:2026-03-26