Update
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# 01-if-else - 条件判断
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### if语句基本语法
|
||||
|
||||
```go
|
||||
if condition {
|
||||
// 当condition为true时执行
|
||||
}
|
||||
```
|
||||
|
||||
### if-else语句
|
||||
|
||||
```go
|
||||
if condition {
|
||||
// 当condition为true时执行
|
||||
} else {
|
||||
// 当condition为false时执行
|
||||
}
|
||||
```
|
||||
|
||||
### if-else if-else链
|
||||
|
||||
```go
|
||||
if condition1 {
|
||||
// condition1为true时执行
|
||||
} else if condition2 {
|
||||
// condition1为false且condition2为true时执行
|
||||
} else {
|
||||
// 所有条件都为false时执行
|
||||
}
|
||||
```
|
||||
|
||||
### 带初始化语句的if
|
||||
|
||||
```go
|
||||
if err := doSomething(); err != nil {
|
||||
// 处理错误
|
||||
}
|
||||
```
|
||||
|
||||
### 逻辑运算符
|
||||
|
||||
- `&&` - 逻辑与(AND)
|
||||
- `||` - 逻辑或(OR)
|
||||
- `!` - 逻辑非(NOT)
|
||||
|
||||
### 重要提示
|
||||
|
||||
- 条件表达式必须是布尔值
|
||||
- Go没有三元运算符,需要使用完整的if-else
|
||||
- if语句后的`{`必须与if在同一行
|
||||
- 条件表达式中可以声明变量(作用域仅限if块内)
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握if语句的基本用法
|
||||
- ✅ 理解if-else if-else链
|
||||
- ✅ 能够使用带初始化语句的if
|
||||
- ✅ 掌握复杂的条件表达式
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func exercise1() {
|
||||
fmt.Println("=== 练习1:简单if判断 ===")
|
||||
|
||||
age := 18
|
||||
|
||||
// 使用if语句,判断age是否大于等于18
|
||||
// 如果是,输出"你已经成年了"
|
||||
if ____ {
|
||||
fmt.Println("你已经成年了")
|
||||
} else {
|
||||
fmt.Println("你还未成年")
|
||||
}
|
||||
}
|
||||
|
||||
func exercise2() {
|
||||
fmt.Println("\n=== 练习2:if-else if-else链 ===")
|
||||
|
||||
score := 85
|
||||
|
||||
// 使用if-else if-else链,根据score判断等级
|
||||
// 90-100: 优秀
|
||||
// 80-89: 良好
|
||||
// 60-79: 及格
|
||||
// 0-59: 不及格
|
||||
if ____ {
|
||||
fmt.Printf("分数: %d, 等级: 优秀\n", score)
|
||||
} else if ____ {
|
||||
fmt.Printf("分数: %d, 等级: 良好\n", score)
|
||||
} else if ____ {
|
||||
fmt.Printf("分数: %d, 等级: 及格\n", score)
|
||||
} else {
|
||||
fmt.Printf("分数: %d, 等级: 不及格\n", score)
|
||||
}
|
||||
}
|
||||
|
||||
func exercise3() string {
|
||||
fmt.Println("\n=== 练习3:带初始化语句的if ===")
|
||||
|
||||
// 使用带初始化语句的if,将字符串"42"转换为整数
|
||||
// 如果转换成功,返回字符串"转换成功: 转换后的值"
|
||||
// 如果转换失败,返回字符串"转换失败"
|
||||
if num, err := strconv.____; ____ {
|
||||
return fmt.Sprintf("转换成功: %d", num)
|
||||
} else {
|
||||
return "转换失败"
|
||||
}
|
||||
}
|
||||
|
||||
func exercise4() string {
|
||||
fmt.Println("\n=== 练习4:复杂条件表达式 ===")
|
||||
|
||||
username := "admin"
|
||||
password := "123456"
|
||||
isActive := true
|
||||
|
||||
// 使用if语句,判断:
|
||||
// 1. 用户名是"admin"
|
||||
// 2. 密码是"123456"
|
||||
// 3. 账户是激活状态
|
||||
// 三个条件都满足时,返回"登录成功",否则返回"登录失败"
|
||||
if ____ && ____ && ____ {
|
||||
return "登录成功"
|
||||
} else {
|
||||
return "登录失败"
|
||||
}
|
||||
}
|
||||
|
||||
func exercise5() bool {
|
||||
fmt.Println("\n=== 练习5:逻辑非和或运算 ===")
|
||||
|
||||
hasPermission := false
|
||||
isAdmin := true
|
||||
|
||||
// 使用if语句,判断"没有权限但可以是管理员"的情况
|
||||
// 提示:使用 ! 或 ||
|
||||
if ____ {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func exercise6() string {
|
||||
fmt.Println("\n=== 练习6:字符串判断 ===")
|
||||
|
||||
email := "test@example.com"
|
||||
|
||||
// 使用if语句判断email是否包含"@"
|
||||
// 提示:使用strings.Contains函数
|
||||
if ____ {
|
||||
return "有效的邮箱地址"
|
||||
} else {
|
||||
return "无效的邮箱地址"
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== if-else 练习 ===\n")
|
||||
|
||||
exercise1()
|
||||
exercise2()
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Println(result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Println(result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %t\n", result5)
|
||||
|
||||
result6 := exercise6()
|
||||
fmt.Println(result6)
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
output := captureOutput(exercise1)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"成年检查", "你已经成年了"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
output := captureOutput(exercise2)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"良好等级检查", "分数: 85, 等级: 良好"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
|
||||
if result != "转换成功: 42" {
|
||||
t.Errorf("期望结果 '转换成功: 42', 实际结果: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
|
||||
if result != "登录成功" {
|
||||
t.Errorf("期望结果 '登录成功', 实际结果: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
|
||||
if result != true {
|
||||
t.Errorf("期望结果 true, 实际结果: %t", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise6(t *testing.T) {
|
||||
result := exercise6()
|
||||
|
||||
if result != "有效的邮箱地址" {
|
||||
t.Errorf("期望结果 '有效的邮箱地址', 实际结果: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== if-else 练习 ===",
|
||||
"练习1:简单if判断",
|
||||
"练习2:if-else if-else链",
|
||||
"练习3:带初始化语句的if",
|
||||
"练习4:复杂条件表达式",
|
||||
"练习5:逻辑非和或运算",
|
||||
"练习6:字符串判断",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
# 02-switch - switch语句
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 基本switch语法
|
||||
|
||||
```go
|
||||
switch value {
|
||||
case value1:
|
||||
// 当value == value1时执行
|
||||
case value2:
|
||||
// 当value == value2时执行
|
||||
default:
|
||||
// 当value不等于任何case时执行
|
||||
}
|
||||
```
|
||||
|
||||
### switch重要特性
|
||||
|
||||
1. **自动break**:Go的switch不需要显式break,执行完case后自动跳出
|
||||
2. **fallthrough**:使用fallthrough关键字继续执行下一个case
|
||||
3. **多值匹配**:一个case可以匹配多个值
|
||||
4. **无表达式的switch**:相当于if-else if-else的替代
|
||||
5. **类型switch**:用于类型断言
|
||||
|
||||
### 多值匹配
|
||||
|
||||
```go
|
||||
switch day {
|
||||
case "Monday", "Tuesday":
|
||||
fmt.Println("工作日")
|
||||
}
|
||||
```
|
||||
|
||||
### fallthrough
|
||||
|
||||
```go
|
||||
switch num {
|
||||
case 1:
|
||||
fmt.Println("one")
|
||||
fallthrough // 继续执行case 2
|
||||
case 2:
|
||||
fmt.Println("two")
|
||||
}
|
||||
```
|
||||
|
||||
### 无表达式的switch
|
||||
|
||||
```go
|
||||
switch {
|
||||
case score >= 90:
|
||||
fmt.Println("优秀")
|
||||
case score >= 80:
|
||||
fmt.Println("良好")
|
||||
}
|
||||
```
|
||||
|
||||
### 类型switch
|
||||
|
||||
```go
|
||||
switch v := i.(type) {
|
||||
case int:
|
||||
fmt.Println("整数")
|
||||
case string:
|
||||
fmt.Println("字符串")
|
||||
}
|
||||
```
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握switch语句的基本用法
|
||||
- ✅ 理解多值匹配和fallthrough
|
||||
- ✅ 学会使用无表达式的switch
|
||||
- ✅ 了解类型switch的使用
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,134 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() {
|
||||
fmt.Println("=== 练习1:基本switch ===")
|
||||
|
||||
day := 3
|
||||
|
||||
// 使用switch语句,根据day的值输出对应的星期
|
||||
// 1: 星期一, 2: 星期二, 3: 星期三, 4: 星期四
|
||||
// 5: 星期五, 6: 星期六, 7: 星期日
|
||||
// 其他: 无效的天数
|
||||
switch ____ {
|
||||
case ____:
|
||||
fmt.Println("星期一")
|
||||
case ____:
|
||||
fmt.Println("星期二")
|
||||
case ____:
|
||||
fmt.Println("星期三")
|
||||
case ____:
|
||||
fmt.Println("星期四")
|
||||
case ____:
|
||||
fmt.Println("星期五")
|
||||
case ____:
|
||||
fmt.Println("星期六")
|
||||
case ____:
|
||||
fmt.Println("星期日")
|
||||
default:
|
||||
fmt.Println("无效的天数")
|
||||
}
|
||||
}
|
||||
|
||||
func exercise2() {
|
||||
fmt.Println("\n=== 练习2:多值匹配 ===")
|
||||
|
||||
month := 1
|
||||
|
||||
// 使用switch语句,根据month的值输出季节
|
||||
// 使用多值匹配(一个case匹配多个值)
|
||||
// 3,4,5: 春季
|
||||
// 6,7,8: 夏季
|
||||
// 9,10,11: 秋季
|
||||
// 12,1,2: 冬季
|
||||
switch ____ {
|
||||
case ____, ____, ____:
|
||||
fmt.Println("春季")
|
||||
case ____, ____, ____:
|
||||
fmt.Println("夏季")
|
||||
case ____, ____, ____:
|
||||
fmt.Println("秋季")
|
||||
case ____, ____, ____:
|
||||
fmt.Println("冬季")
|
||||
default:
|
||||
fmt.Println("无效的月份")
|
||||
}
|
||||
}
|
||||
|
||||
func exercise3() {
|
||||
fmt.Println("\n=== 练习3:无表达式的switch ===")
|
||||
|
||||
score := 92
|
||||
|
||||
// 使用无表达式的switch,根据score判断等级
|
||||
// 90-100: 优秀
|
||||
// 80-89: 良好
|
||||
// 60-79: 及格
|
||||
// 0-59: 不及格
|
||||
switch {
|
||||
case ____:
|
||||
fmt.Printf("分数: %d, 等级: 优秀\n", score)
|
||||
case ____:
|
||||
fmt.Printf("分数: %d, 等级: 良好\n", score)
|
||||
case ____:
|
||||
fmt.Printf("分数: %d, 等级: 及格\n", score)
|
||||
case ____:
|
||||
fmt.Printf("分数: %d, 等级: 不及格\n", score)
|
||||
}
|
||||
}
|
||||
|
||||
func exercise4() {
|
||||
fmt.Println("\n=== 练习4:fallthrough ===")
|
||||
|
||||
num := 1
|
||||
|
||||
// 使用switch和fallthrough,当num=1时:
|
||||
// 输出"one"然后继续执行case 2输出"two"
|
||||
// 提示:在case 1的末尾添加fallthrough
|
||||
switch ____ {
|
||||
case 1:
|
||||
fmt.Println("one")
|
||||
____
|
||||
case 2:
|
||||
fmt.Println("two")
|
||||
case 3:
|
||||
fmt.Println("three")
|
||||
}
|
||||
}
|
||||
|
||||
func exercise5() string {
|
||||
fmt.Println("\n=== 练习5:switch返回值 ===")
|
||||
|
||||
status := 200
|
||||
|
||||
// 使用switch语句,根据HTTP状态码返回对应的描述
|
||||
// 200: OK
|
||||
// 404: Not Found
|
||||
// 500: Internal Server Error
|
||||
// 其他: Unknown Status
|
||||
var result string
|
||||
switch ____ {
|
||||
case 200:
|
||||
result = "OK"
|
||||
case 404:
|
||||
result = "Not Found"
|
||||
case 500:
|
||||
result = "Internal Server Error"
|
||||
default:
|
||||
result = "Unknown Status"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== switch 练习 ===\n")
|
||||
|
||||
exercise1()
|
||||
exercise2()
|
||||
exercise3()
|
||||
exercise4()
|
||||
|
||||
result := exercise5()
|
||||
fmt.Println(result)
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
output := captureOutput(exercise1)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"星期三检查", "星期三"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
output := captureOutput(exercise2)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"春季检查", "春季"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
output := captureOutput(exercise3)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"优秀等级检查", "分数: 92, 等级: 优秀"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
output := captureOutput(exercise4)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"one输出检查", "one"},
|
||||
{"two输出检查", "two"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
|
||||
if result != "OK" {
|
||||
t.Errorf("期望结果 'OK', 实际结果: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== switch 练习 ===",
|
||||
"练习1:基本switch",
|
||||
"练习2:多值匹配",
|
||||
"练习3:无表达式的switch",
|
||||
"练习4:fallthrough",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
# 03-for-loop - for循环
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
Go语言只有一种循环语句:`for`,但它有多种形式。
|
||||
|
||||
### 基本for循环(类似C的for)
|
||||
|
||||
```go
|
||||
for init; condition; post {
|
||||
// 循环体
|
||||
}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```go
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Println(i)
|
||||
}
|
||||
```
|
||||
|
||||
### while形式(省略init和post)
|
||||
|
||||
```go
|
||||
for condition {
|
||||
// 循环体
|
||||
}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```go
|
||||
i := 0
|
||||
for i < 10 {
|
||||
fmt.Println(i)
|
||||
i++
|
||||
}
|
||||
```
|
||||
|
||||
### 无限循环
|
||||
|
||||
```go
|
||||
for {
|
||||
// 循环体,需要break或return才能退出
|
||||
}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```go
|
||||
for {
|
||||
fmt.Println("无限循环")
|
||||
break // 退出循环
|
||||
}
|
||||
```
|
||||
|
||||
### for-range(遍历数组、切片、map、字符串)
|
||||
|
||||
```go
|
||||
// 遍历切片或数组
|
||||
for index, value := range slice {
|
||||
fmt.Printf("索引: %d, 值: %v\n", index, value)
|
||||
}
|
||||
|
||||
// 遍历map
|
||||
for key, value := range m {
|
||||
fmt.Printf("键: %v, 值: %v\n", key, value)
|
||||
}
|
||||
|
||||
// 遍历字符串(字符索引和rune)
|
||||
for index, char := range "你好" {
|
||||
fmt.Printf("索引: %d, 字符: %c\n", index, char)
|
||||
}
|
||||
```
|
||||
|
||||
### break和continue
|
||||
|
||||
- `break`:跳出整个循环
|
||||
- `continue`:跳过本次循环,进入下一次循环
|
||||
|
||||
### 重要提示
|
||||
|
||||
- Go没有while循环,for可以替代while
|
||||
- 循环变量在每次迭代中会重新声明
|
||||
- for-range遍历字符串时,index是字节位置,value是rune
|
||||
- 如果不需要索引或值,可以使用`_`忽略
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握for循环的几种形式
|
||||
- ✅ 理解for-range的用法
|
||||
- ✅ 能够使用break和continue
|
||||
- ✅ 学会遍历字符串、切片和map
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() int {
|
||||
fmt.Println("=== 练习1:基本for循环 ===")
|
||||
|
||||
sum := 0
|
||||
|
||||
// 使用for循环,计算1到10的和(包括10)
|
||||
// 初始化: i := 1
|
||||
// 条件: i <= 10
|
||||
// 后置: i++
|
||||
for ____; ____; ____ {
|
||||
sum += i
|
||||
}
|
||||
|
||||
fmt.Printf("1到10的和: %d\n", sum)
|
||||
return sum
|
||||
}
|
||||
|
||||
func exercise2() int {
|
||||
fmt.Println("\n=== 练习2:while形式的for循环 ===")
|
||||
|
||||
sum := 0
|
||||
i := 1
|
||||
|
||||
// 使用while形式的for循环,计算1到5的乘积
|
||||
// 提示:省略初始化和后置语句
|
||||
for ____ {
|
||||
sum *= i
|
||||
i++
|
||||
}
|
||||
|
||||
fmt.Printf("1到5的乘积: %d\n", sum)
|
||||
return sum
|
||||
}
|
||||
|
||||
func exercise3() []int {
|
||||
fmt.Println("\n=== 练习3:break和continue ===")
|
||||
|
||||
nums := []int{}
|
||||
|
||||
// 使用for循环,遍历1到10
|
||||
// 如果数字能被3整除,跳过(使用continue)
|
||||
// 如果数字大于8,停止循环(使用break)
|
||||
i := 1
|
||||
for i <= 10 {
|
||||
if ____ {
|
||||
i++
|
||||
____
|
||||
}
|
||||
if ____ {
|
||||
____
|
||||
}
|
||||
nums = append(nums, i)
|
||||
i++
|
||||
}
|
||||
|
||||
fmt.Printf("符合条件的数字: %v\n", nums)
|
||||
return nums
|
||||
}
|
||||
|
||||
func exercise4() string {
|
||||
fmt.Println("\n=== 练习4:for-range遍历切片 ===")
|
||||
|
||||
fruits := []string{"苹果", "香蕉", "橙子"}
|
||||
result := ""
|
||||
|
||||
// 使用for-range遍历切片,格式化输出
|
||||
// 提示:range会返回索引和值,示例: "0: 苹果"
|
||||
for ____, ____ := range ____ {
|
||||
result += fmt.Sprintf("%d: %s ", index, value)
|
||||
}
|
||||
|
||||
fmt.Printf("水果列表: %s\n", result)
|
||||
return result
|
||||
}
|
||||
|
||||
func exercise5() string {
|
||||
fmt.Println("\n=== 练习5:for-range遍历map ===")
|
||||
|
||||
scores := map[string]int{"张三": 90, "李四": 85, "王五": 95}
|
||||
result := ""
|
||||
|
||||
// 使用for-range遍历map,格式化输出
|
||||
// 提示:range遍历map时,返回的是键和值
|
||||
for ____, ____ := range ____ {
|
||||
result += fmt.Sprintf("%s: %d ", name, score)
|
||||
}
|
||||
|
||||
fmt.Printf("成绩表: %s\n", result)
|
||||
return result
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== for循环 练习 ===\n")
|
||||
|
||||
exercise1()
|
||||
exercise2()
|
||||
exercise3()
|
||||
exercise4()
|
||||
exercise5()
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
output := captureOutput(exercise1)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"求和检查", "1到10的和: 55"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
output := captureOutput(exercise2)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"乘积检查", "1到5的乘积: 120"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !strings.Contains(output, tt.expected) {
|
||||
t.Errorf("期望输出包含 '%s', 但实际输出: %s", tt.expected, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if len(result) != 6 {
|
||||
t.Errorf("期望结果长度为6, 实际长度: %d", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if !strings.Contains(result, "0: 苹果") {
|
||||
t.Errorf("期望包含 '0: 苹果', 实际结果: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
requiredNames := []string{"张三", "李四", "王五"}
|
||||
for _, name := range requiredNames {
|
||||
if !strings.Contains(result, name) {
|
||||
t.Errorf("期望包含 '%s', 实际结果: %s", name, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== for循环 练习 ===",
|
||||
"练习1:基本for循环",
|
||||
"练习2:while形式的for循环",
|
||||
"练习3:break和continue",
|
||||
"练习4:for-range遍历切片",
|
||||
"练习5:for-range遍历map",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
# 04-defer - defer机制
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### defer基本语法
|
||||
|
||||
`defer`语句会将函数调用推迟到当前函数返回之前执行。
|
||||
|
||||
```go
|
||||
func example() {
|
||||
defer fmt.Println("最后执行")
|
||||
fmt.Println("先执行")
|
||||
}
|
||||
// 输出:
|
||||
// 先执行
|
||||
// 最后执行
|
||||
```
|
||||
|
||||
### defer的执行顺序
|
||||
|
||||
多个defer语句按照**后进先出(LIFO)**的顺序执行。
|
||||
|
||||
```go
|
||||
func example() {
|
||||
defer fmt.Println(1)
|
||||
defer fmt.Println(2)
|
||||
defer fmt.Println(3)
|
||||
}
|
||||
// 输出:
|
||||
// 3
|
||||
// 2
|
||||
// 1
|
||||
```
|
||||
|
||||
### defer的参数求值
|
||||
|
||||
defer语句中的函数参数在defer声明时就被求值(立即求值),而不是在实际执行时。
|
||||
|
||||
```go
|
||||
func example() {
|
||||
i := 0
|
||||
defer fmt.Println(i) // i=0 在此时被求值
|
||||
i = 10
|
||||
}
|
||||
// 输出: 0 (而不是10)
|
||||
```
|
||||
|
||||
### defer修改返回值
|
||||
|
||||
使用具名返回值时,defer可以修改返回值。
|
||||
|
||||
```go
|
||||
func example() (result int) {
|
||||
defer func() {
|
||||
result = 100 // 修改返回值
|
||||
}()
|
||||
return 50
|
||||
}
|
||||
// 返回: 100
|
||||
```
|
||||
|
||||
### defer的常见用途
|
||||
|
||||
1. **关闭资源**:
|
||||
```go
|
||||
file, err := os.Open("file.txt")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close() // 确保文件被关闭
|
||||
```
|
||||
|
||||
2. **释放锁**:
|
||||
```go
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock() // 确保锁被释放
|
||||
```
|
||||
|
||||
3. **恢复panic**:
|
||||
```go
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("恢复:", r)
|
||||
}
|
||||
}()
|
||||
```
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 理解defer的执行时机
|
||||
- ✅ 掌握defer的执行顺序(LIFO)
|
||||
- ✅ 了解defer参数的立即求值特性
|
||||
- ✅ 学会defer的常见应用场景
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() {
|
||||
fmt.Println("=== 练习1:defer基本用法 ===")
|
||||
|
||||
// 使用defer,在函数结束时打印"函数结束"
|
||||
____
|
||||
fmt.Println("函数执行中")
|
||||
}
|
||||
|
||||
func exercise2() {
|
||||
fmt.Println("\n=== 练习2:defer执行顺序 ===")
|
||||
|
||||
// 使用多个defer语句,按照1-2-3的顺序声明
|
||||
// 观察输出的顺序(应该是3-2-1)
|
||||
____
|
||||
____
|
||||
____
|
||||
fmt.Println("正常执行")
|
||||
}
|
||||
|
||||
func exercise3() int {
|
||||
fmt.Println("\n=== 练习3:defer修改返回值 ===")
|
||||
|
||||
// 使用具名返回值result
|
||||
// defer函数中将result修改为100
|
||||
// return返回50
|
||||
var ____ int = ____
|
||||
|
||||
defer func() {
|
||||
____ = ____
|
||||
}()
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() {
|
||||
fmt.Println("\n=== 练习4:defer参数求值 ===")
|
||||
|
||||
i := 0
|
||||
|
||||
// 使用defer打印i的值
|
||||
// 注意:defer声明时就对参数求值了
|
||||
____
|
||||
|
||||
i = 10
|
||||
fmt.Println("修改i为:", i)
|
||||
}
|
||||
|
||||
func exercise5() {
|
||||
fmt.Println("\n=== 练习5:实际场景 - 模拟资源管理 ===")
|
||||
|
||||
// 模拟打开资源
|
||||
resource := "文件句柄"
|
||||
fmt.Println("打开:", resource)
|
||||
|
||||
// 使用defer在函数结束时关闭资源
|
||||
defer func() {
|
||||
fmt.Println("关闭:", ____)
|
||||
}()
|
||||
|
||||
fmt.Println("使用:", resource)
|
||||
}
|
||||
|
||||
func exercise6() {
|
||||
fmt.Println("\n=== 练习6:defer捕获变量的值 ===")
|
||||
|
||||
// 使用循环声明多个defer
|
||||
// 每个defer捕获当前i的值并打印
|
||||
// 提示:使用闭包或立即求值
|
||||
for i := 1; i <= 3; i++ {
|
||||
____ func(n int) {
|
||||
fmt.Printf("defer输出: %d\n", n)
|
||||
}(____)
|
||||
fmt.Println("循环输出:", i)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== defer 练习 ===\n")
|
||||
|
||||
exercise1()
|
||||
exercise2()
|
||||
fmt.Printf("练习3返回值: %d\n", exercise3())
|
||||
exercise4()
|
||||
exercise5()
|
||||
exercise6()
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
output := captureOutput(exercise1)
|
||||
|
||||
if !strings.Contains(output, "函数结束") {
|
||||
t.Error("期望输出包含 '函数结束'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
output := captureOutput(exercise2)
|
||||
|
||||
expected := []string{"正常执行", "defer输出: 3", "defer输出: 2", "defer输出: 1"}
|
||||
for _, exp := range expected {
|
||||
if !strings.Contains(output, exp) {
|
||||
t.Errorf("期望输出包含 '%s', 实际: %s", exp, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != 100 {
|
||||
t.Errorf("期望返回值 100, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
output := captureOutput(exercise4)
|
||||
|
||||
// defer应该在函数结束时打印i的初始值0
|
||||
if !strings.Contains(output, "defer输出: 0") {
|
||||
t.Error("期望输出包含 'defer输出: 0'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
output := captureOutput(exercise5)
|
||||
|
||||
if !strings.Contains(output, "关闭: 文件句柄") {
|
||||
t.Error("期望输出包含 '关闭: 文件句柄'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise6(t *testing.T) {
|
||||
output := captureOutput(exercise6)
|
||||
|
||||
expected := []string{"循环输出: 1", "循环输出: 2", "循环输出: 3"}
|
||||
for _, exp := range expected {
|
||||
if !strings.Contains(output, exp) {
|
||||
t.Errorf("期望输出包含 '%s', 实际: %s", exp, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== defer 练习 ===",
|
||||
"练习1:defer基本用法",
|
||||
"练习2:defer执行顺序",
|
||||
"练习3:defer修改返回值",
|
||||
"练习4:defer参数求值",
|
||||
"练习5:实际场景 - 模拟资源管理",
|
||||
"练习6:defer捕获变量的值",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Stage 02 - 控制结构
|
||||
|
||||
学习Go语言的控制结构,包括条件判断、循环和defer机制。
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本阶段后,你将掌握:
|
||||
- ✅ if/else条件判断
|
||||
- ✅ switch语句(包括类型switch)
|
||||
- ✅ for循环的各种形式(Go只有for)
|
||||
- ✅ defer的执行时机和作用
|
||||
|
||||
## 练习列表
|
||||
|
||||
1. **01-if-else** - 条件判断
|
||||
2. **02-switch** - switch语句
|
||||
3. **03-for-loop** - for循环
|
||||
4. **04-defer** - defer机制
|
||||
|
||||
## 预计用时
|
||||
|
||||
每练习15-20分钟,本阶段约1-1.5小时
|
||||
|
||||
## 备注
|
||||
|
||||
- Go语言没有while循环,for可以替代while
|
||||
- switch不需要break,但可以使用fallthrough
|
||||
- defer的执行顺序是LIFO(后进先出)
|
||||
Reference in New Issue
Block a user