Go 从 0 到精通 · 第 05 课:循环结构 for
Go 从 0 到精通 · 第 05 课:循环结构 for
学习定位:这是整套 Go 教程的第 5 课。
前置要求:已经完成第 4 课,掌握了if、else if、else、switch以及逻辑运算符的使用。
本课目标:掌握 Go 中唯一的循环关键字for的所有常见用法,理解break、continue的控制方式,初步接触for range遍历。
1. 本课你要解决的核心问题
前面你学会了让程序"做判断",但程序还不会"重复做事"。循环就是让程序能反复执行某段逻辑的机制。
你需要搞明白以下问题:
- 为什么 Go 只有
for一种循环关键字 - 经典三段式
for怎么写 - 条件式
for怎么模拟其他语言的while - 无限循环怎么写,什么时候用
break和continue分别做什么for range是什么,怎么遍历- 循环中有哪些常见坑
学完这一课,你就掌握了 Go 的全部基础控制流,可以写出有判断、有循环的完整程序逻辑了。
2. Go 只有 for,没有 while 和 do...while
这是 Go 和很多其他语言最大的区别之一。
在 C、Java、Python 等语言里,循环通常有好几种关键字:for、while、do...while。
Go 只保留了 for 一个关键字,但通过不同的写法,它能覆盖所有这些场景。
Go 为什么这样设计:
- 减少概念数量,降低心智负担
- 一种结构多种用法,更统一
- 符合 Go"少即是多"的设计哲学
你接下来会看到,for 虽然只有一个关键字,但它的表达能力非常强。
3. 经典三段式 for
这是最常见、最基础的循环写法。
3.1 基本语法
1 | for 初始语句; 条件表达式; 后置语句 { |
三个部分的含义:
- 初始语句:循环开始前执行一次,通常用来声明计数器
- 条件表达式:每次循环前判断,为
true就继续,为false就结束 - 后置语句:每次循环体执行完后执行,通常用来更新计数器
3.2 最简单的例子
1 | package main |
输出:
1 | 第 0 次循环 |
执行流程是:
i := 0:声明变量i,初始值为0- 判断
i < 5,成立,执行循环体 - 执行完循环体后,执行
i++(i变成1) - 再次判断
i < 5,成立,继续 - 重复,直到
i等于5,条件不成立,循环结束
3.3 i++ 是什么
i++ 等价于 i = i + 1,表示让 i 的值增加 1。
同理,i-- 等价于 i = i - 1。
Go 中的 ++ 和 -- 有一个重要限制:
i++和i--是语句,不是表达式。
这意味着你不能写这样的代码:
1 | // 错误:Go 不允许 |
也不存在 ++i 这种前置写法。Go 只支持后置的 i++ 和 i--,而且它们只能单独作为一条语句使用。
3.4 循环变量的作用域
在 for 初始语句中用 := 声明的变量,作用域仅限于这个 for 循环:
1 | package main |
这和 if 初始化语句的作用域规则一样:变量只在它所属的语句块中有效。
3.5 倒序循环
1 | package main |
输出:
1 | 5 |
初始语句、条件、后置语句可以根据需要灵活调整。
3.6 步长不是 1
1 | package main |
输出:
1 | 0 |
i += 3 表示每次循环后 i 增加 3。你可以用任何合法的赋值语句作为后置语句。
4. 条件式 for:Go 版的 while
4.1 基本写法
如果你省略初始语句和后置语句,只保留条件表达式,for 就变成了其他语言中的 while:
1 | package main |
输出:
1 | count = 0 |
这等价于其他语言的:
1 | while (count < 5) { |
Go 里没有 while 关键字,但 for 条件 { } 完全能替代它。
4.2 典型使用场景
条件式 for 适合循环次数不确定的场景,例如:
- 不断读取用户输入,直到用户输入特定值
- 不断尝试某个操作,直到成功
- 数据处理到某个条件时停止
1 | package main |
输出:
1 | 累加到 14 时,总和首次达到 105 |
5. 无限循环
5.1 基本写法
如果 for 后面什么都不写,就是无限循环:
1 | for { |
这等价于其他语言的 while(true)。
5.2 无限循环不一定是 bug
无限循环在很多场景下是正常的设计模式,例如:
- 服务器持续监听请求
- 不断等待用户输入
- 定时任务持续运行
关键是:无限循环通常要配合 break 或 return 来提供退出条件。
5.3 实际例子:用户输入循环
1 | package main |
运行效果:
1 | 请输入命令(输入 quit 退出):hello |
break 让循环立刻终止,程序继续执行循环后面的代码。
6. break:跳出循环
6.1 基本用法
break 的作用是:立刻终止当前所在的循环。
1 | package main |
输出:
1 | 0 |
当 i 等于 5 时,break 执行,循环立刻结束,程序继续打印"循环结束"。
6.2 break 只能跳出最内层循环
如果有嵌套循环,break 只能跳出它直接所在的那一层循环:
1 | package main |
输出:
1 | i=0 j=0 |
当 j == 2 时,break 只跳出内层循环,外层循环继续。
如果需要跳出外层循环,可以使用标签(label),下面会讲。
7. continue:跳过本次,进入下一次
7.1 基本用法
continue 的作用是:跳过当前这一次循环的剩余部分,直接进入下一次循环。
1 | package main |
输出:
1 | 1 |
当 i 是偶数时,continue 执行,跳过 fmt.Println(i),直接进入下一次循环。
7.2 break 和 continue 的区别
break:直接终止整个循环continue:跳过本次循环的剩余代码,进入下一次循环
用一个比喻来理解:
break是"我不干了,走人"continue是"这次算了,下一个"
8. 标签(Label):跳出多层循环
8.1 问题场景
有时候你在嵌套循环里需要一次跳出所有层循环,但 break 默认只跳出最内层。
8.2 使用标签
1 | package main |
输出:
1 | i=0 j=0 |
outer: 是一个标签,放在外层循环前面。break outer 表示跳出带 outer 标签的那层循环。
continue 也可以配合标签使用,表示跳到外层循环的下一次迭代。
标签在实际开发中不算非常常用,但遇到嵌套循环场景时它是一个有用的工具。
9. for range:遍历利器
9.1 什么是 for range
for range 是 Go 中专门用来遍历数据结构的语法。它可以遍历:
- 字符串
- 数组
- 切片
- map
- channel
这一课先用字符串来感受它的基本用法,后面学到切片、map 时会深入使用。
9.2 遍历字符串
1 | package main |
输出:
1 | 下标 0:字符 H |
for range 每次迭代会返回两个值:
- 第一个值:当前元素的索引(下标)
- 第二个值:当前元素的值
9.3 只需要索引时
如果你只需要索引,不需要值,可以只写一个变量:
1 | package main |
9.4 只需要值时
如果你只需要值,不需要索引,用 _ 忽略索引:
1 | package main |
输出:
1 | H e l l o |
_ 是 Go 的空白标识符,表示"我不关心这个值"。
9.5 for range 遍历中文字符串
1 | package main |
输出:
1 | 下标 0:字符 你 |
注意下标不是连续的 0, 1, 2, 3,而是 0, 3, 6, 7。
这是因为 for range 遍历字符串时,是按 Unicode 码点(rune)遍历的。中文字符在 UTF-8 编码中通常占 3 个字节,所以下标会跳跃。
这个知识点在后面第 11 课《字符串、byte 与 rune》中会深入讲解。你现在先知道这个现象就好。
10. 循环的常见模式
10.1 累加求和
1 | package main |
输出:
1 | 1 到 100 的和是: 5050 |
10.2 打印九九乘法表
1 | package main |
输出:
1 | 1×1=1 |
这里用了嵌套循环。%-4d 是格式化动词,表示左对齐、占 4 个字符宽度。
10.3 查找特定值
1 | package main |
这是一个很常见的模式:在循环中查找某个值,找到后用 break 退出。
11. 一段综合示例
把本课的核心知识串到一个程序里:
1 | package main |
输出:
1 | === 经典 for === |
12. 常见坑总结
12.1 死循环忘记更新条件
1 | // 危险:count 永远不会变 |
这会导致程序永远不停,必须强制终止。
写条件式 for 时,一定要确保循环体内有改变条件的逻辑。
12.2 三段式 for 的条件写错导致不执行
1 | // 循环体一次都不执行 |
因为初始值 10 已经不满足 i < 5,循环体直接跳过。
这不是报错,而是逻辑问题,调试时需要注意。
12.3 在循环中修改循环变量
1 | // 不推荐这样写 |
虽然 Go 允许这样做,但手动在循环体内修改循环变量会让代码难以理解和维护。
除非有明确的理由,否则不要在循环体内修改三段式 for 的计数器。
12.4 for range 的值是拷贝
1 | package main |
输出:
1 | int32 int32 int32 |
for range 遍历字符串时,每个字符的类型是 int32(也就是 rune),而不是 byte。
而且你拿到的值是一份拷贝,修改它不会影响原始数据。这个概念在后面学切片时会更加重要。
12.5 以为 Go 有 while 关键字
Go 没有 while。如果你写了 while,编译器会直接报错。
用 for 条件 { } 来替代 while。
12.6 break 和 continue 搞混
break:终止整个循环continue:跳过本次,继续下一次
如果你想的是"跳过当前这个,继续处理下一个",用 continue。
如果你想的是"不再循环了,结束",用 break。
13. 本课练习
一定要亲手写,不要只看。
练习 1:打印 1 到 20
要求:
- 用经典三段式
for打印 1 到 20 的所有整数 - 每个数字占一行
练习 2:累加求和
要求:
- 计算 1 + 2 + 3 + … + 100 的和
- 打印结果
练习 3:只打印奇数
要求:
- 打印 1 到 50 之间的所有奇数
- 用
continue跳过偶数
练习 4:猜数字游戏
要求:
- 程序内部固定一个"答案"数字(比如
42) - 用无限循环不断读取用户输入
- 如果猜对了,打印"恭喜你猜对了!"并退出
- 如果猜大了,提示"太大了"
- 如果猜小了,提示"太小了"
练习 5:九九乘法表
要求:
- 用嵌套循环打印九九乘法表
- 格式要对齐整齐
练习 6:用 for range 遍历字符串
要求:
- 定义一个包含中文和英文的字符串,例如
"Hello你好" - 用
for range遍历,打印每个字符和它的下标 - 观察中文字符的下标是否连续,自己解释原因
练习 7:找出 100 以内的所有素数
要求:
- 打印 2 到 100 之间的所有素数
- 用嵌套循环判断一个数是否是素数
- 素数的定义:只能被 1 和它自身整除的大于 1 的整数
提示:内层循环从 2 到 i-1,如果都不能整除,就是素数。
练习 8:break 标签练习
要求:
- 写一个双层嵌套循环
- 在内层循环中使用
break加标签,一次跳出两层循环 - 打印跳出后的信息
14. 自测题
不看文档,试着回答:
14.1 概念题
- Go 有几种循环关键字?
- 经典三段式
for的三个部分分别是什么? - 怎么用
for模拟其他语言的while? - 怎么写无限循环?
break和continue的区别是什么?break在嵌套循环中默认跳出几层?- 怎么用标签跳出多层循环?
for range遍历字符串时,每次迭代返回什么?i++在 Go 中是表达式还是语句?- 为什么
for range遍历中文字符串时下标不连续?
如果你能流畅回答这些问题,说明这一课你已经真正理解了。
15. 本课总结
这一课你学到的是让程序具备"重复执行"能力的核心机制。
你现在应该已经理解:
- Go 只有
for一种循环关键字,但能覆盖所有循环场景 - 经典三段式
for i := 0; i < n; i++ { }是最基础的用法 - 省略初始和后置语句的
for 条件 { }等价于其他语言的while for { }是无限循环,通常配合break使用break终止循环,continue跳过本次break默认只跳出最内层循环,用标签可以跳出多层for range用于遍历字符串、数组、切片、map 等数据结构for range遍历字符串时按rune(Unicode 码点)遍历,中文下标会跳跃i++是语句不是表达式,不存在++i的写法
到这里,你已经掌握了 Go 的全部基础控制流:顺序执行、条件判断(if/switch)、循环(for)。接下来就可以开始学习函数了。
16. 下一课预告
下一课我们进入:函数基础。
会重点讲:
- 函数的定义和调用
- 参数和返回值
- 多返回值是什么,为什么 Go 这样设计
- 命名返回值
- 可变参数
- 函数是"一等公民"的初步理解
- 新手常见坑
学完下一课,你就能把重复的逻辑封装成函数,让代码更有组织、更容易复用了。





