Explorar el Código

feat: 新增第四课循环例程与编译运行说明

zhuts hace 4 días
padre
commit
50d08f1399
Se han modificado 3 ficheros con 218 adiciones y 4 borrados
  1. 8 4
      README.md
  2. 149 0
      lessons/04_loops/README.md
  3. 61 0
      lessons/04_loops/main.go

+ 8 - 4
README.md

@@ -18,9 +18,12 @@
     ├── 02_variables/       # 第 02 课:变量、常量与基础类型
     │   ├── README.md       # 知识点、预期输出与手敲练习
     │   └── main.go         # 带逐节注释的参考代码
-    └── 03_conditions/      # 第 03 课:if 条件判断
-        ├── README.md       # 语法、编译运行与边界练习
-        └── main.go         # 分支、比较和逻辑运算
+    ├── 03_conditions/      # 第 03 课:if 条件判断
+    │   ├── README.md       # 语法、编译运行与边界练习
+    │   └── main.go         # 分支、比较和逻辑运算
+    └── 04_loops/           # 第 04 课:for 循环
+        ├── README.md       # 循环语法、编译运行与练习
+        └── main.go         # 累加、跳过、退出和字符串遍历
 ```
 
 根目录不放例程代码。各课共享根目录的 `go.mod`,不需要逐课初始化模块,也不需要 `go.work`。当前模块路径 `example.com/go-study` 是学习用标识,不必与 Git 地址相同。
@@ -32,8 +35,9 @@
 | 01 | [第一个 Go 程序](./lessons/01_hello/README.md) | 输出、变量、函数、首次测试 | 已建立 |
 | 02 | [变量、常量与基础类型](./lessons/02_variables/README.md) | 声明、赋值、零值、类型转换 | 已建立 |
 | 03 | [if 条件判断](./lessons/03_conditions/README.md) | 条件分支、比较、逻辑运算 | 已建立 |
+| 04 | [for 循环](./lessons/04_loops/README.md) | 三段式、条件循环、break、continue、range | 已建立 |
 
-后续按 `04_loops` 等编号逐步新增独立目录,这些后续目录目前尚未创建。不一次性铺开后续课程,也不把新例程写进旧例程的入口文件。
+后续按编号逐步新增独立目录。不一次性铺开后续课程,也不把新例程写进旧例程的入口文件。
 
 ## 快速开始
 

+ 149 - 0
lessons/04_loops/README.md

@@ -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)

+ 61 - 0
lessons/04_loops/main.go

@@ -0,0 +1,61 @@
+package main
+
+import "fmt"
+
+func main() {
+	// 1. 三段式循环:初始化;继续循环的条件;每轮结束后的操作。
+	// 执行顺序:初始化 -> 判断条件 -> 循环体 -> i++ -> 再判断条件。
+	fmt.Println("=== 三段式循环 ===")
+	for i := 1; i <= 3; i++ {
+		fmt.Printf("第 %d 次学习 Go\n", i)
+	}
+	// i 只在上面的 for 语句内有效,循环外不能使用它。
+
+	// 2. 累加:每轮把当前数字加入 sum。
+	fmt.Println("\n=== 累加求和 ===")
+	sum := 0
+	for n := 1; n <= 5; n++ {
+		sum += n // 等价于 sum = sum + n。
+	}
+	fmt.Printf("1 到 5 的和:%d\n", sum)
+
+	// 3. 只有条件的循环:相当于 C 中的 while。
+	// Go 没有 while 关键字;注意更新变量,避免死循环。
+	fmt.Println("\n=== 条件循环 ===")
+	count := 3
+	for count > 0 {
+		fmt.Printf("倒计时:%d\n", count)
+		count--
+	}
+	fmt.Println("开始!")
+
+	// 4. continue:跳过本轮剩余代码,进入下一轮。
+	// 三段式循环中,continue 之后仍会执行更新语句 n++。
+	fmt.Println("\n=== continue:只输出奇数 ===")
+	for n := 1; n <= 5; n++ {
+		if n%2 == 0 { // % 是取余运算符,偶数除以 2 的余数是 0。
+			continue
+		}
+		fmt.Printf("奇数:%d\n", n)
+	}
+
+	// 5. 不写条件的 for 会一直循环,需要通过 break 等方式退出。
+	// break 结束当前循环,不是结束整个 main 函数。
+	fmt.Println("\n=== break:结束循环 ===")
+	attempt := 1
+	for {
+		fmt.Printf("第 %d 次尝试\n", attempt)
+		if attempt == 3 {
+			break
+		}
+		attempt++
+	}
+	fmt.Println("循环已结束,后续代码继续执行")
+
+	// 6. range 遍历字符串:每轮得到字符的字节索引和 rune 值。
+	// %c 将 rune 按字符输出;中文字符不一定只占一个字节。
+	fmt.Println("\n=== range:遍历字符串 ===")
+	for index, char := range "Go语言" {
+		fmt.Printf("字节索引:%d,字符:%c\n", index, char)
+	}
+}