Files
golang/golang-learning/02-control-flow/03-for-loops.go
2025-08-24 01:01:26 +08:00

633 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
03-for-loops.go - Go 语言 for 循环详解
学习目标:
1. 掌握 for 循环的各种形式
2. 理解 break 和 continue 的使用
3. 学会使用标签控制嵌套循环
4. 了解无限循环的写法
5. 掌握循环的实际应用场景
知识点:
- 传统 for 循环
- while 风格的 for 循环
- 无限循环
- break 和 continue
- 标签 (label)
- 嵌套循环
- 循环优化技巧
*/
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Println("=== Go 语言 for 循环详解 ===\n")
// 演示传统 for 循环
demonstrateTraditionalFor()
// 演示 while 风格的 for 循环
demonstrateWhileStyleFor()
// 演示无限循环
demonstrateInfiniteLoop()
// 演示 break 和 continue
demonstrateBreakContinue()
// 演示嵌套循环和标签
demonstrateNestedLoopsAndLabels()
// 演示循环的实际应用
demonstratePracticalExamples()
// 演示循环优化技巧
demonstrateOptimizationTips()
}
// demonstrateTraditionalFor 演示传统 for 循环
func demonstrateTraditionalFor() {
fmt.Println("1. 传统 for 循环:")
// 基本的 for 循环
fmt.Printf(" 基本 for 循环 (0-4):\n")
for i := 0; i < 5; i++ {
fmt.Printf(" i = %d\n", i)
}
// 倒序循环
fmt.Printf(" 倒序循环 (5-1):\n")
for i := 5; i > 0; i-- {
fmt.Printf(" i = %d\n", i)
}
// 步长为 2 的循环
fmt.Printf(" 步长为 2 的循环:\n")
for i := 0; i <= 10; i += 2 {
fmt.Printf(" i = %d\n", i)
}
// 多个变量的循环
fmt.Printf(" 多变量循环:\n")
for i, j := 0, 10; i < j; i, j = i+1, j-1 {
fmt.Printf(" i = %d, j = %d\n", i, j)
}
// 计算累加和
sum := 0
for i := 1; i <= 10; i++ {
sum += i
}
fmt.Printf(" 1到10的累加和: %d\n", sum)
// 计算阶乘
factorial := 1
n := 5
for i := 1; i <= n; i++ {
factorial *= i
}
fmt.Printf(" %d的阶乘: %d\n", n, factorial)
fmt.Println()
}
// demonstrateWhileStyleFor 演示 while 风格的 for 循环
func demonstrateWhileStyleFor() {
fmt.Println("2. while 风格的 for 循环:")
fmt.Printf(" Go 没有 while 关键字,使用 for 代替\n")
// 模拟 while 循环
fmt.Printf(" 模拟 while 循环:\n")
count := 0
for count < 5 {
fmt.Printf(" count = %d\n", count)
count++
}
// 条件判断循环
fmt.Printf(" 条件判断循环 (猜数字):\n")
target := 7
guess := 1
attempts := 0
for guess != target {
attempts++
fmt.Printf(" 第 %d 次猜测: %d", attempts, guess)
if guess < target {
fmt.Printf(" (太小了)\n")
guess += 2
} else {
fmt.Printf(" (太大了)\n")
guess--
}
}
fmt.Printf(" 恭喜!第 %d 次猜中了: %d\n", attempts+1, guess)
// 读取用户输入直到满足条件
fmt.Printf(" 模拟输入验证:\n")
password := ""
attempts = 0
correctPassword := "123456"
// 模拟用户输入
inputs := []string{"111", "222", "123456"}
for password != correctPassword && attempts < 3 {
password = inputs[attempts] // 模拟用户输入
attempts++
fmt.Printf(" 第 %d 次输入密码: %s", attempts, password)
if password == correctPassword {
fmt.Printf(" (正确)\n")
} else {
fmt.Printf(" (错误)\n")
}
}
if password == correctPassword {
fmt.Printf(" 登录成功!\n")
} else {
fmt.Printf(" 登录失败,超过最大尝试次数\n")
}
fmt.Println()
}
// demonstrateInfiniteLoop 演示无限循环
func demonstrateInfiniteLoop() {
fmt.Println("3. 无限循环:")
fmt.Printf(" 无限循环的写法: for { ... }\n")
fmt.Printf(" 通常配合 break 使用\n")
// 无限循环示例1: 服务器主循环模拟
fmt.Printf(" 示例1 - 服务器主循环模拟:\n")
requestCount := 0
for {
requestCount++
fmt.Printf(" 处理第 %d 个请求\n", requestCount)
// 模拟处理请求
if requestCount >= 3 {
fmt.Printf(" 服务器关闭\n")
break
}
}
// 无限循环示例2: 菜单系统
fmt.Printf(" 示例2 - 菜单系统模拟:\n")
menuOptions := []string{"查看余额", "转账", "退出"}
choice := 0
for {
fmt.Printf(" 请选择操作:\n")
for i, option := range menuOptions {
fmt.Printf(" %d. %s\n", i+1, option)
}
// 模拟用户选择
choice = (choice % 3) + 1
fmt.Printf(" 用户选择: %d\n", choice)
switch choice {
case 1:
fmt.Printf(" 当前余额: 1000元\n")
case 2:
fmt.Printf(" 转账功能暂未开放\n")
case 3:
fmt.Printf(" 谢谢使用,再见!\n")
return // 或者使用 break
}
// 为了演示,只循环一次
break
}
fmt.Println()
}
// demonstrateBreakContinue 演示 break 和 continue
func demonstrateBreakContinue() {
fmt.Println("4. break 和 continue:")
// break 示例
fmt.Printf(" break - 跳出循环:\n")
for i := 0; i < 10; i++ {
if i == 5 {
fmt.Printf(" 遇到 %d跳出循环\n", i)
break
}
fmt.Printf(" i = %d\n", i)
}
// continue 示例
fmt.Printf(" continue - 跳过当前迭代:\n")
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // 跳过偶数
}
fmt.Printf(" 奇数: %d\n", i)
}
// 实际应用:处理数据时跳过无效值
fmt.Printf(" 实际应用 - 处理数据跳过无效值:\n")
data := []int{1, -2, 3, 0, 5, -6, 7, 8, 0, 9}
sum := 0
validCount := 0
for i, value := range data {
if value <= 0 {
fmt.Printf(" 跳过无效值 data[%d] = %d\n", i, value)
continue
}
sum += value
validCount++
fmt.Printf(" 处理有效值 data[%d] = %d\n", i, value)
}
fmt.Printf(" 有效数据个数: %d总和: %d平均值: %.2f\n",
validCount, sum, float64(sum)/float64(validCount))
// 查找第一个满足条件的元素
fmt.Printf(" 查找第一个大于 50 的数:\n")
numbers := []int{10, 25, 30, 55, 60, 75}
found := false
for i, num := range numbers {
fmt.Printf(" 检查 numbers[%d] = %d\n", i, num)
if num > 50 {
fmt.Printf(" 找到第一个大于 50 的数: %d\n", num)
found = true
break
}
}
if !found {
fmt.Printf(" 没有找到大于 50 的数\n")
}
fmt.Println()
}
// demonstrateNestedLoopsAndLabels 演示嵌套循环和标签
func demonstrateNestedLoopsAndLabels() {
fmt.Println("5. 嵌套循环和标签:")
// 基本嵌套循环
fmt.Printf(" 基本嵌套循环 - 乘法表:\n")
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
fmt.Printf(" %d × %d = %d\n", i, j, i*j)
}
}
// 使用标签控制嵌套循环
fmt.Printf(" 使用标签控制嵌套循环:\n")
outer:
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
fmt.Printf(" i=%d, j=%d\n", i, j)
if i == 2 && j == 2 {
fmt.Printf(" 在 i=2, j=2 时跳出外层循环\n")
break outer
}
}
}
// 标签 continue 示例
fmt.Printf(" 标签 continue 示例:\n")
outerContinue:
for i := 1; i <= 3; i++ {
fmt.Printf(" 外层循环 i = %d\n", i)
for j := 1; j <= 3; j++ {
if i == 2 && j == 2 {
fmt.Printf(" 在 i=2, j=2 时跳过外层循环的当前迭代\n")
continue outerContinue
}
fmt.Printf(" 内层循环 j = %d\n", j)
}
fmt.Printf(" 外层循环 i = %d 结束\n", i)
}
// 矩阵搜索示例
fmt.Printf(" 矩阵搜索示例:\n")
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
target := 5
found := false
search:
for i := 0; i < len(matrix); i++ {
for j := 0; j < len(matrix[i]); j++ {
fmt.Printf(" 检查 matrix[%d][%d] = %d\n", i, j, matrix[i][j])
if matrix[i][j] == target {
fmt.Printf(" 找到目标值 %d 在位置 [%d][%d]\n", target, i, j)
found = true
break search
}
}
}
if !found {
fmt.Printf(" 未找到目标值 %d\n", target)
}
fmt.Println()
}
// demonstratePracticalExamples 演示循环的实际应用
func demonstratePracticalExamples() {
fmt.Println("6. 循环的实际应用:")
// 示例1: 数组/切片处理
fmt.Printf(" 示例1 - 数组处理:\n")
scores := []int{85, 92, 78, 96, 88, 73, 91}
// 计算平均分
total := 0
for _, score := range scores {
total += score
}
average := float64(total) / float64(len(scores))
fmt.Printf(" 平均分: %.2f\n", average)
// 找出最高分和最低分
maxScore, minScore := scores[0], scores[0]
for _, score := range scores {
if score > maxScore {
maxScore = score
}
if score < minScore {
minScore = score
}
}
fmt.Printf(" 最高分: %d最低分: %d\n", maxScore, minScore)
// 统计及格人数
passCount := 0
for _, score := range scores {
if score >= 80 {
passCount++
}
}
fmt.Printf(" 及格人数: %d/%d\n", passCount, len(scores))
// 示例2: 字符串处理
fmt.Printf(" 示例2 - 字符串处理:\n")
text := "Hello, 世界! 123"
// 统计字符类型
letters, digits, others := 0, 0, 0
for _, char := range text {
switch {
case (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char > 127:
letters++
case char >= '0' && char <= '9':
digits++
default:
others++
}
}
fmt.Printf(" 字符串: \"%s\"\n", text)
fmt.Printf(" 字母: %d数字: %d其他: %d\n", letters, digits, others)
// 示例3: 数学计算
fmt.Printf(" 示例3 - 数学计算 (斐波那契数列):\n")
n := 10
fmt.Printf(" 前 %d 个斐波那契数:\n", n)
a, b := 0, 1
for i := 0; i < n; i++ {
fmt.Printf(" F(%d) = %d\n", i, a)
a, b = b, a+b
}
// 示例4: 模拟游戏
fmt.Printf(" 示例4 - 简单猜数字游戏:\n")
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(10) + 1
maxAttempts := 3
// 模拟玩家猜测
guesses := []int{5, 8, secretNumber}
for attempt := 1; attempt <= maxAttempts; attempt++ {
guess := guesses[attempt-1] // 模拟用户输入
fmt.Printf(" 第 %d 次猜测: %d", attempt, guess)
if guess == secretNumber {
fmt.Printf(" - 恭喜你猜对了!\n")
break
} else if guess < secretNumber {
fmt.Printf(" - 太小了\n")
} else {
fmt.Printf(" - 太大了\n")
}
if attempt == maxAttempts {
fmt.Printf(" 游戏结束!正确答案是: %d\n", secretNumber)
}
}
// 示例5: 数据验证
fmt.Printf(" 示例5 - 批量数据验证:\n")
emails := []string{
"user@example.com",
"invalid-email",
"test@domain.org",
"@invalid.com",
"valid@test.net",
}
validEmails := 0
for i, email := range emails {
isValid := validateEmail(email)
fmt.Printf(" 邮箱 %d: %-20s - ", i+1, email)
if isValid {
fmt.Printf("有效\n")
validEmails++
} else {
fmt.Printf("无效\n")
}
}
fmt.Printf(" 有效邮箱数量: %d/%d\n", validEmails, len(emails))
fmt.Println()
}
// demonstrateOptimizationTips 演示循环优化技巧
func demonstrateOptimizationTips() {
fmt.Println("7. 循环优化技巧:")
// 技巧1: 减少重复计算
fmt.Printf(" 技巧1 - 减少重复计算:\n")
data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 不好的写法:每次都计算 len(data)
fmt.Printf(" 不推荐的写法 (每次计算长度):\n")
for i := 0; i < len(data); i++ {
// len(data) 在每次迭代时都会被调用
fmt.Printf(" data[%d] = %d\n", i, data[i])
if i >= 2 { // 为了演示,只显示前几个
break
}
}
// 好的写法:预先计算长度
fmt.Printf(" 推荐的写法 (预先计算长度):\n")
length := len(data)
for i := 0; i < length; i++ {
fmt.Printf(" data[%d] = %d\n", i, data[i])
if i >= 2 {
break
}
}
// 技巧2: 使用 range 遍历
fmt.Printf(" 技巧2 - 使用 range 遍历 (更简洁):\n")
for i, value := range data {
fmt.Printf(" data[%d] = %d\n", i, value)
if i >= 2 {
break
}
}
// 技巧3: 提前退出
fmt.Printf(" 技巧3 - 提前退出优化:\n")
numbers := []int{2, 4, 6, 7, 8, 10, 12}
// 查找第一个奇数
for i, num := range numbers {
fmt.Printf(" 检查 numbers[%d] = %d", i, num)
if num%2 == 1 {
fmt.Printf(" - 找到第一个奇数: %d\n", num)
break // 找到后立即退出,不继续遍历
}
fmt.Printf(" - 偶数,继续查找\n")
}
// 技巧4: 批量处理
fmt.Printf(" 技巧4 - 批量处理:\n")
largeData := make([]int, 20)
for i := range largeData {
largeData[i] = i + 1
}
batchSize := 5
fmt.Printf(" 批量处理数据 (批次大小: %d):\n", batchSize)
for i := 0; i < len(largeData); i += batchSize {
end := i + batchSize
if end > len(largeData) {
end = len(largeData)
}
batch := largeData[i:end]
fmt.Printf(" 处理批次 %d-%d: %v\n", i, end-1, batch)
// 模拟批量处理
batchSum := 0
for _, value := range batch {
batchSum += value
}
fmt.Printf(" 批次总和: %d\n", batchSum)
}
// 技巧5: 避免不必要的操作
fmt.Printf(" 技巧5 - 避免不必要的操作:\n")
matrix2 := [][]int{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
}
// 只处理对角线元素
fmt.Printf(" 只处理矩阵对角线元素:\n")
for i := 0; i < len(matrix2) && i < len(matrix2[0]); i++ {
fmt.Printf(" 对角线元素 [%d][%d] = %d\n", i, i, matrix2[i][i])
}
fmt.Println()
}
// 辅助函数
func validateEmail(email string) bool {
// 简单的邮箱验证(实际应用中应该使用正则表达式)
if len(email) < 5 {
return false
}
hasAt := false
hasDot := false
atPos := -1
for i, char := range email {
if char == '@' {
if hasAt || i == 0 || i == len(email)-1 {
return false
}
hasAt = true
atPos = i
} else if char == '.' && hasAt && i > atPos+1 && i < len(email)-1 {
hasDot = true
}
}
return hasAt && hasDot
}
/*
运行这个程序:
go run 03-for-loops.go
学习要点:
1. Go 只有 for 循环,没有 while 和 do-while
2. for 循环有三种形式传统形式、while 形式、无限循环形式
3. break 用于跳出循环continue 用于跳过当前迭代
4. 标签可以用来控制嵌套循环的跳转
5. range 关键字提供了遍历数组、切片、字符串等的便捷方式
for 循环的三种形式:
1. for init; condition; post { ... } // 传统形式
2. for condition { ... } // while 形式
3. for { ... } // 无限循环
循环控制:
1. break: 跳出当前循环
2. continue: 跳过当前迭代,继续下一次迭代
3. 标签: 可以跳出或跳过指定的外层循环
优化建议:
1. 减少循环内的重复计算
2. 使用 range 遍历集合类型
3. 适当使用 break 提前退出
4. 考虑批量处理大量数据
5. 避免不必要的嵌套循环
常见应用场景:
1. 数组/切片遍历和处理
2. 数值计算(累加、阶乘等)
3. 字符串处理
4. 数据验证和过滤
5. 算法实现
6. 游戏循环
7. 服务器主循环
注意事项:
1. 避免无限循环(除非有明确的退出条件)
2. 注意循环变量的作用域
3. 在嵌套循环中正确使用标签
4. 考虑循环的时间复杂度
5. 合理使用 break 和 continue
*/