|
|
@@ -0,0 +1,149 @@
|
|
|
+# 第 04 课:for 循环
|
|
|
+
|
|
|
+## 学习目标
|
|
|
+
|
|
|
+第三课学会了根据条件选择分支,这一课学习重复执行代码。按 [main.go](./main.go) 中的 1~6 节逐段手敲,每完成一节就编译运行一次。
|
|
|
+
|
|
|
+本课独立存放,共享根目录的 `go.mod`,只使用标准库,不需要新增依赖。
|
|
|
+
|
|
|
+## 1. 三段式循环
|
|
|
+
|
|
|
+```go
|
|
|
+for i := 1; i <= 3; i++ {
|
|
|
+ fmt.Println(i)
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+和 C 的 `for (int i = 1; i <= 3; i++)` 类似,但 Go 不需要外面的圆括号,大括号不能省略。
|
|
|
+
|
|
|
+执行顺序:
|
|
|
+
|
|
|
+1. `i := 1`:初始化一次。
|
|
|
+2. `i <= 3`:每轮执行前判断,为 false 时退出。
|
|
|
+3. 执行大括号中的循环体。
|
|
|
+4. `i++`:本轮结束后加一,然后回到第 2 步。
|
|
|
+
|
|
|
+这里的 `i` 只在 for 语句内有效。Go 的 `i++` 是独立语句,不能写成 `x := i++`,也没有 `++i` 写法。
|
|
|
+
|
|
|
+## 2. 条件循环与无限循环
|
|
|
+
|
|
|
+Go 没有 `while` 关键字,用 `for 条件` 表达:
|
|
|
+
|
|
|
+```go
|
|
|
+count := 3
|
|
|
+for count > 0 {
|
|
|
+ fmt.Println(count)
|
|
|
+ count--
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+不写条件时就是无限循环:
|
|
|
+
|
|
|
+```go
|
|
|
+for {
|
|
|
+ // 需要用 break 等方式退出,否则会一直执行。
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+如果忘记更新条件相关的变量,可能发生死循环。在终端按 `Ctrl + C` 可以中断正在运行的程序。
|
|
|
+
|
|
|
+## 3. break 与 continue
|
|
|
+
|
|
|
+| 语句 | 作用 |
|
|
|
+| --- | --- |
|
|
|
+| `break` | 结束当前循环,继续执行循环后面的代码 |
|
|
|
+| `continue` | 跳过本轮剩余代码,进入下一轮 |
|
|
|
+
|
|
|
+本课只用单层循环;后续遇到嵌套时,要注意无标签的 break / continue 不会同时控制所有层。
|
|
|
+
|
|
|
+在三段式循环中,`continue` 后仍执行更新语句。只有条件的循环则要自己保证变量得到更新,避免 `continue` 跳过更新造成死循环。
|
|
|
+
|
|
|
+`n % 2` 表示除以 2 的余数;余数为 0 可以判断整数是偶数。`sum += n` 等价于 `sum = sum + n`。
|
|
|
+
|
|
|
+## 4. range 遍历字符串
|
|
|
+
|
|
|
+```go
|
|
|
+for index, char := range "Go语言" {
|
|
|
+ fmt.Printf("字节索引:%d,字符:%c\n", index, char)
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- `index` 是本次 Unicode 码点在字符串中的起始字节索引,不是第几个字。
|
|
|
+- `char` 是 `rune`(`int32` 的别名),这里用 `%c` 输出字符。
|
|
|
+- UTF-8 下的“语”“言”各占 3 字节,因此索引是 `0、1、2、5`,不是 `0、1、2、3`。
|
|
|
+- 如果只需要字符,不需要索引,可以写 `for _, char := range "Go语言"`,`_` 表示忽略该值。
|
|
|
+
|
|
|
+这里先接触简单字符串遍历,不要求本课深入掌握 Unicode。下一课再学习数组与切片的遍历。
|
|
|
+
|
|
|
+## 编译并运行
|
|
|
+
|
|
|
+在**仓库根目录**执行:
|
|
|
+
|
|
|
+```powershell
|
|
|
+New-Item -ItemType Directory -Force bin/04_loops | Out-Null
|
|
|
+go build -o ./bin/04_loops/loops.exe ./lessons/04_loops
|
|
|
+.\bin\04_loops\loops.exe
|
|
|
+```
|
|
|
+
|
|
|
+修改源码后需要重新编译,已有 exe 不会自动更新。
|
|
|
+
|
|
|
+快速编译并运行:
|
|
|
+
|
|
|
+```powershell
|
|
|
+go run ./lessons/04_loops
|
|
|
+```
|
|
|
+
|
|
|
+也可以从根目录进入本课,再运行:
|
|
|
+
|
|
|
+```powershell
|
|
|
+Set-Location lessons/04_loops
|
|
|
+go run .
|
|
|
+```
|
|
|
+
|
|
|
+## 预期输出
|
|
|
+
|
|
|
+```text
|
|
|
+=== 三段式循环 ===
|
|
|
+第 1 次学习 Go
|
|
|
+第 2 次学习 Go
|
|
|
+第 3 次学习 Go
|
|
|
+
|
|
|
+=== 累加求和 ===
|
|
|
+1 到 5 的和:15
|
|
|
+
|
|
|
+=== 条件循环 ===
|
|
|
+倒计时:3
|
|
|
+倒计时:2
|
|
|
+倒计时:1
|
|
|
+开始!
|
|
|
+
|
|
|
+=== continue:只输出奇数 ===
|
|
|
+奇数:1
|
|
|
+奇数:3
|
|
|
+奇数:5
|
|
|
+
|
|
|
+=== break:结束循环 ===
|
|
|
+第 1 次尝试
|
|
|
+第 2 次尝试
|
|
|
+第 3 次尝试
|
|
|
+循环已结束,后续代码继续执行
|
|
|
+
|
|
|
+=== range:遍历字符串 ===
|
|
|
+字节索引:0,字符:G
|
|
|
+字节索引:1,字符:o
|
|
|
+字节索引:2,字符:语
|
|
|
+字节索引:5,字符:言
|
|
|
+```
|
|
|
+
|
|
|
+## 动手练习
|
|
|
+
|
|
|
+- [ ] 把第一段改成输出 5 次,观察 `<=` 与 `<` 的区别。
|
|
|
+- [ ] 计算 1 到 100 的和,核对结果 `5050`。
|
|
|
+- [ ] 把倒计时改为从 5 开始。
|
|
|
+- [ ] 修改 continue 的条件,改为只输出偶数 `2、4`。
|
|
|
+- [ ] 把 break 的退出条件改为第 5 次,确认循环结束后的提示仍然输出。
|
|
|
+- [ ] 用 `for _, char := range "你好Go"` 只输出字符。
|
|
|
+
|
|
|
+如果另外手敲一份,放进本课的 `practice/` 子目录并在根目录用 `go run ./lessons/04_loops/practice` 运行,不要在同一个包中声明两个 `main` 函数。
|
|
|
+
|
|
|
+[上一课:if 条件判断](../03_conditions/README.md) · [学习总览](../../README.md)
|