Skip to content

Go 语言循环语句

循环语句用于重复执行一段代码直到满足某个条件。Go 语言只有一种循环关键字 for,但它提供了多种形式来适应不同的循环需求。

🔄 for 循环的基本形式

经典三段式 for 循环

go
package main

import "fmt"

func main() {
    // 基本的 for 循环:初始化; 条件; 后置语句
    fmt.Println("数字 1 到 5:")
    for i := 1; i <= 5; i++ {
        fmt.Printf("%d ", i)
    }
    fmt.Println()
    
    // 倒序循环
    fmt.Println("倒数 5 到 1:")
    for i := 5; i >= 1; i-- {
        fmt.Printf("%d ", i)
    }
    fmt.Println()
    
    // 步长不为 1 的循环
    fmt.Println("偶数 2 到 10:")
    for i := 2; i <= 10; i += 2 {
        fmt.Printf("%d ", i)
    }
    fmt.Println()
    
    // 嵌套循环 - 乘法表
    fmt.Println("\n九九乘法表:")
    for i := 1; i <= 9; i++ {
        for j := 1; j <= i; j++ {
            fmt.Printf("%d*%d=%d ", j, i, i*j)
        }
        fmt.Println()
    }
}

条件循环(类似 while)

go
func main() {
    // 省略初始化和后置语句,只保留条件
    count := 0
    fmt.Println("条件循环:")
    for count < 5 {
        fmt.Printf("count = %d\n", count)
        count++
    }
    
    // 无限循环(需要用 break 跳出)
    fmt.Println("\n无限循环示例:")
    counter := 0
    for {
        if counter >= 3 {
            break  // 跳出循环
        }
        fmt.Printf("无限循环第 %d\n", counter+1)
        counter++
    }
    
    // 模拟 do-while 循环
    fmt.Println("\n模拟 do-while:")
    num := 10
    for {
        fmt.Printf("num = %d\n", num)
        num--
        if num < 8 {
            break
        }
    }
}

🎯 range 循环

遍历切片和数组

go
func main() {
    // 遍历切片
    fruits := []string{"苹果", "香蕉", "橙子", "葡萄"}
    
    // 方式1:获取索引和值
    fmt.Println("遍历水果(索引和值):")
    for index, fruit := range fruits {
        fmt.Printf("索引 %d: %s\n", index, fruit)
    }
    
    // 方式2:只获取索引
    fmt.Println("\n只获取索引:")
    for index := range fruits {
        fmt.Printf("索引 %d\n", index)
    }
    
    // 方式3:只获取值
    fmt.Println("\n只获取值:")
    for _, fruit := range fruits {
        fmt.Printf("水果: %s\n", fruit)
    }
    
    // 遍历数组
    numbers := [5]int{10, 20, 30, 40, 50}
    fmt.Println("\n遍历数组:")
    for i, num := range numbers {
        fmt.Printf("numbers[%d] = %d\n", i, num)
    }
}

遍历映射(map)

go
func main() {
    // 遍历 map
    studentGrades := map[string]int{
        "Alice": 95,
        "Bob":   87,
        "Carol": 92,
        "David": 78,
    }
    
    fmt.Println("学生成绩:")
    for name, grade := range studentGrades {
        fmt.Printf("%s: %d\n", name, grade)
    }
    
    // 只获取键
    fmt.Println("\n学生姓名:")
    for name := range studentGrades {
        fmt.Printf("学生: %s\n", name)
    }
    
    // 只获取值
    fmt.Println("\n所有成绩:")
    for _, grade := range studentGrades {
        fmt.Printf("成绩: %d\n", grade)
    }
    
    // 注意:map 的遍历顺序是随机的
    fmt.Println("\n多次遍历顺序可能不同:")
    for i := 0; i < 3; i++ {
        fmt.Printf("第%d次遍历: ", i+1)
        for name := range studentGrades {
            fmt.Printf("%s ", name)
        }
        fmt.Println()
    }
}

遍历字符串

go
import "unicode/utf8"

func main() {
    // 遍历字符串(按字节)
    str := "Hello, 世界!"
    
    fmt.Println("按字节遍历:")
    for i := 0; i < len(str); i++ {
        fmt.Printf("字节 %d: %c (0x%02x)\n", i, str[i], str[i])
    }
    
    // 遍历字符串(按字符)
    fmt.Println("\n按字符遍历:")
    for index, char := range str {
        fmt.Printf("位置 %d: %c (Unicode: %U)\n", index, char, char)
    }
    
    // 统计字符数
    fmt.Printf("\n字符串长度: %d 字节\n", len(str))
    fmt.Printf("字符数量: %d 个字符\n", utf8.RuneCountInString(str))
    
    // 中文字符串示例
    chinese := "你好世界"
    fmt.Printf("\n中文字符串: %s\n", chinese)
    fmt.Printf("字节长度: %d\n", len(chinese))
    
    for i, char := range chinese {
        fmt.Printf("位置 %d: %c\n", i, char)
    }
}

遍历通道(channel)

go
func main() {
    // 创建并填充通道
    ch := make(chan int, 5)
    
    // 发送数据到通道
    go func() {
        for i := 1; i <= 5; i++ {
            ch <- i * i  // 发送平方数
        }
        close(ch)  // 关闭通道
    }()
    
    // 遍历通道
    fmt.Println("从通道接收数据:")
    for value := range ch {
        fmt.Printf("接收到: %d\n", value)
    }
    
    fmt.Println("通道已关闭,遍历结束")
}

🛑 循环控制语句

break 语句

go
func main() {
    // break 跳出当前循环
    fmt.Println("使用 break 跳出循环:")
    for i := 1; i <= 10; i++ {
        if i == 6 {
            break  // 当 i 等于 6 时跳出循环
        }
        fmt.Printf("%d ", i)
    }
    fmt.Println("\n循环结束")
    
    // 在嵌套循环中使用 break
    fmt.Println("\n嵌套循环中的 break:")
    for i := 1; i <= 3; i++ {
        fmt.Printf("外层循环 i = %d\n", i)
        for j := 1; j <= 3; j++ {
            if j == 2 {
                break  // 只跳出内层循环
            }
            fmt.Printf("  内层循环 j = %d\n", j)
        }
    }
    
    // 查找数组中的元素
    numbers := []int{1, 3, 5, 7, 9, 2, 4, 6, 8}
    target := 7
    
    fmt.Printf("\n在数组中查找 %d:\n", target)
    for i, num := range numbers {
        if num == target {
            fmt.Printf("找到 %d 在索引 %d 位置\n", target, i)
            break
        }
        fmt.Printf("检查索引 %d: %d\n", i, num)
    }
}

continue 语句

go
func main() {
    // continue 跳过当前迭代,继续下一次迭代
    fmt.Println("打印奇数 (1-10):")
    for i := 1; i <= 10; i++ {
        if i%2 == 0 {
            continue  // 跳过偶数
        }
        fmt.Printf("%d ", i)
    }
    fmt.Println()
    
    // 处理数组时跳过特定值
    scores := []int{85, -1, 92, 88, -1, 76, 94}
    validScores := 0
    totalScore := 0
    
    fmt.Println("\n处理成绩(跳过无效成绩 -1):")
    for i, score := range scores {
        if score == -1 {
            fmt.Printf("索引 %d: 跳过无效成绩\n", i)
            continue
        }
        fmt.Printf("索引 %d: 有效成绩 %d\n", i, score)
        validScores++
        totalScore += score
    }
    
    if validScores > 0 {
        average := float64(totalScore) / float64(validScores)
        fmt.Printf("平均成绩: %.2f\n", average)
    }
}

标签和 goto

go
func main() {
    // 使用标签控制嵌套循环
    fmt.Println("使用标签的嵌套循环:")
    
OuterLoop:  // 标签
    for i := 1; i <= 3; i++ {
        for j := 1; j <= 3; j++ {
            if i == 2 && j == 2 {
                fmt.Printf("在 i=%d, j=%d 时跳出所有循环\n", i, j)
                break OuterLoop  // 跳出到标签位置
            }
            fmt.Printf("i=%d, j=%d\n", i, j)
        }
    }
    fmt.Println("嵌套循环结束")
    
    // continue 配合标签
    fmt.Println("\n使用标签的 continue:")
    
ContinueOuter:
    for i := 1; i <= 3; i++ {
        for j := 1; j <= 3; j++ {
            if j == 2 {
                fmt.Printf("在 i=%d, j=%d 时跳过外层循环的剩余内层循环\n", i, j)
                continue ContinueOuter
            }
            fmt.Printf("i=%d, j=%d\n", i, j)
        }
        fmt.Printf("外层循环 i=%d 的内层循环完成\n", i)
    }
}

🎯 实际应用示例

数据处理和统计

go
import (
    "fmt"
    "math"
    "sort"
)

func main() {
    // 学生成绩数据
    students := map[string][]int{
        "Alice": {85, 92, 78, 88, 90},
        "Bob":   {76, 81, 69, 85, 79},
        "Carol": {95, 89, 92, 96, 93},
        "David": {72, 68, 75, 71, 77},
    }
    
    // 处理每个学生的成绩
    for name, scores := range students {
        fmt.Printf("\n学生: %s\n", name)
        fmt.Printf("原始成绩: %v\n", scores)
        
        // 计算总分和平均分
        total := 0
        for _, score := range scores {
            total += score
        }
        average := float64(total) / float64(len(scores))
        
        // 找最高分和最低分
        maxScore := scores[0]
        minScore := scores[0]
        for _, score := range scores {
            if score > maxScore {
                maxScore = score
            }
            if score < minScore {
                minScore = score
            }
        }
        
        // 计算方差
        variance := 0.0
        for _, score := range scores {
            diff := float64(score) - average
            variance += diff * diff
        }
        variance /= float64(len(scores))
        standardDev := math.Sqrt(variance)
        
        // 计算等级
        grade := calculateGrade(average)
        
        fmt.Printf("总分: %d\n", total)
        fmt.Printf("平均分: %.2f\n", average)
        fmt.Printf("最高分: %d\n", maxScore)
        fmt.Printf("最低分: %d\n", minScore)
        fmt.Printf("标准差: %.2f\n", standardDev)
        fmt.Printf("等级: %s\n", grade)
    }
    
    // 班级整体统计
    fmt.Println("\n=== 班级整体统计 ===")
    allScores := []float64{}
    for _, scores := range students {
        total := 0
        for _, score := range scores {
            total += score
        }
        average := float64(total) / float64(len(scores))
        allScores = append(allScores, average)
    }
    
    // 排序平均分
    sort.Float64s(allScores)
    fmt.Printf("平均分排序: %.2f\n", allScores)
    
    classTotal := 0.0
    for _, avg := range allScores {
        classTotal += avg
    }
    classAverage := classTotal / float64(len(allScores))
    fmt.Printf("班级平均分: %.2f\n", classAverage)
}

func calculateGrade(average float64) string {
    switch {
    case average >= 90:
        return "A"
    case average >= 80:
        return "B"
    case average >= 70:
        return "C"
    case average >= 60:
        return "D"
    default:
        return "F"
    }
}

素数生成器

go
import "math"

func main() {
    // 生成前20个素数
    fmt.Println("前20个素数:")
    primes := generatePrimes(20)
    for i, prime := range primes {
        fmt.Printf("第%d个素数: %d\n", i+1, prime)
    }
    
    // 找100以内的所有素数
    fmt.Println("\n100以内的素数:")
    primesUnder100 := sieveOfEratosthenes(100)
    for i, prime := range primesUnder100 {
        if i > 0 && i%10 == 0 {
            fmt.Println()
        }
        fmt.Printf("%3d ", prime)
    }
    fmt.Println()
}

// 生成前 n 个素数
func generatePrimes(n int) []int {
    primes := []int{}
    num := 2
    
    for len(primes) < n {
        if isPrime(num) {
            primes = append(primes, num)
        }
        num++
    }
    
    return primes
}

// 判断是否为素数
func isPrime(n int) bool {
    if n < 2 {
        return false
    }
    if n == 2 {
        return true
    }
    if n%2 == 0 {
        return false
    }
    
    // 只需检查到 sqrt(n)
    sqrtN := int(math.Sqrt(float64(n)))
    for i := 3; i <= sqrtN; i += 2 {
        if n%i == 0 {
            return false
        }
    }
    return true
}

// 埃拉托斯特尼筛法
func sieveOfEratosthenes(max int) []int {
    // 创建布尔数组
    isPrime := make([]bool, max+1)
    for i := range isPrime {
        isPrime[i] = true
    }
    isPrime[0] = false
    isPrime[1] = false
    
    // 筛法
    for i := 2; i*i <= max; i++ {
        if isPrime[i] {
            // 标记 i 的倍数为非素数
            for j := i * i; j <= max; j += i {
                isPrime[j] = false
            }
        }
    }
    
    // 收集素数
    primes := []int{}
    for i := 2; i <= max; i++ {
        if isPrime[i] {
            primes = append(primes, i)
        }
    }
    
    return primes
}

文本处理和分析

go
import (
    "fmt"
    "strings"
    "unicode"
)

func main() {
    text := `Go语言是Google开发的开源编程语言。
它具有简洁的语法、高效的性能和强大的并发能力。
Go适用于云原生应用、微服务、Web开发等多个领域。
学习Go语言,你可以构建现代化的软件系统。`
    
    fmt.Println("原文本:")
    fmt.Println(text)
    fmt.Println()
    
    // 文本统计
    analyzer := NewTextAnalyzer(text)
    analyzer.Analyze()
    analyzer.PrintStatistics()
}

type TextAnalyzer struct {
    text        string
    lines       []string
    words       []string
    characters  int
    letters     int
    digits      int
    spaces      int
    punctuation int
    wordCount   map[string]int
}

func NewTextAnalyzer(text string) *TextAnalyzer {
    return &TextAnalyzer{
        text:      text,
        wordCount: make(map[string]int),
    }
}

func (ta *TextAnalyzer) Analyze() {
    // 按行分割
    ta.lines = strings.Split(ta.text, "\n")
    
    // 字符统计
    for _, char := range ta.text {
        ta.characters++
        
        switch {
        case unicode.IsLetter(char):
            ta.letters++
        case unicode.IsDigit(char):
            ta.digits++
        case unicode.IsSpace(char):
            ta.spaces++
        case unicode.IsPunct(char):
            ta.punctuation++
        }
    }
    
    // 单词统计
    for _, line := range ta.lines {
        words := strings.Fields(line)
        for _, word := range words {
            // 清理标点符号
            cleanWord := ""
            for _, char := range word {
                if unicode.IsLetter(char) || unicode.IsDigit(char) {
                    cleanWord += string(char)
                }
            }
            
            if cleanWord != "" {
                cleanWord = strings.ToLower(cleanWord)
                ta.words = append(ta.words, cleanWord)
                ta.wordCount[cleanWord]++
            }
        }
    }
}

func (ta *TextAnalyzer) PrintStatistics() {
    fmt.Println("=== 文本分析结果 ===")
    fmt.Printf("行数: %d\n", len(ta.lines))
    fmt.Printf("总字符数: %d\n", ta.characters)
    fmt.Printf("字母数: %d\n", ta.letters)
    fmt.Printf("数字数: %d\n", ta.digits)
    fmt.Printf("空格数: %d\n", ta.spaces)
    fmt.Printf("标点符号数: %d\n", ta.punctuation)
    fmt.Printf("单词总数: %d\n", len(ta.words))
    fmt.Printf("不重复单词数: %d\n", len(ta.wordCount))
    
    // 词频统计(显示前10个)
    fmt.Println("\n词频统计 (前10个):")
    
    type wordFreq struct {
        word  string
        count int
    }
    
    var frequencies []wordFreq
    for word, count := range ta.wordCount {
        frequencies = append(frequencies, wordFreq{word, count})
    }
    
    // 按频率排序
    for i := 0; i < len(frequencies)-1; i++ {
        for j := i + 1; j < len(frequencies); j++ {
            if frequencies[i].count < frequencies[j].count {
                frequencies[i], frequencies[j] = frequencies[j], frequencies[i]
            }
        }
    }
    
    // 显示前10个
    maxDisplay := 10
    if len(frequencies) < maxDisplay {
        maxDisplay = len(frequencies)
    }
    
    for i := 0; i < maxDisplay; i++ {
        fmt.Printf("%d. %s: %d\n", i+1, frequencies[i].word, frequencies[i].count)
    }
}

💡 性能优化技巧

循环优化

go
import (
    "fmt"
    "time"
)

func main() {
    // 测试数据
    size := 1000000
    data := make([]int, size)
    for i := range data {
        data[i] = i
    }
    
    // 方法1:普通循环
    start := time.Now()
    sum1 := 0
    for i := 0; i < len(data); i++ {
        sum1 += data[i]
    }
    duration1 := time.Since(start)
    
    // 方法2:range 循环
    start = time.Now()
    sum2 := 0
    for _, value := range data {
        sum2 += value
    }
    duration2 := time.Since(start)
    
    // 方法3:预先计算长度
    start = time.Now()
    sum3 := 0
    length := len(data)
    for i := 0; i < length; i++ {
        sum3 += data[i]
    }
    duration3 := time.Since(start)
    
    fmt.Printf("普通循环: 结果=%d, 耗时=%v\n", sum1, duration1)
    fmt.Printf("range循环: 结果=%d, 耗时=%v\n", sum2, duration2)
    fmt.Printf("预计算长度: 结果=%d, 耗时=%v\n", sum3, duration3)
    
    // 避免在循环中进行重复计算
    fmt.Println("\n避免重复计算示例:")
    
    // ❌ 不好的做法
    start = time.Now()
    count1 := 0
    for i := 0; i < 10000; i++ {
        for j := 0; j < len(data)/1000; j++ {  // 每次都计算 len(data)
            count1++
        }
    }
    badDuration := time.Since(start)
    
    // ✅ 好的做法
    start = time.Now()
    count2 := 0
    innerLen := len(data) / 1000  // 预先计算
    for i := 0; i < 10000; i++ {
        for j := 0; j < innerLen; j++ {
            count2++
        }
    }
    goodDuration := time.Since(start)
    
    fmt.Printf("重复计算: 次数=%d, 耗时=%v\n", count1, badDuration)
    fmt.Printf("预先计算: 次数=%d, 耗时=%v\n", count2, goodDuration)
    fmt.Printf("性能提升: %.2fx\n", float64(badDuration)/float64(goodDuration))
}

🎓 小结

本章我们全面学习了 Go 语言的循环语句:

  • for 循环:三段式循环、条件循环、无限循环
  • range 循环:遍历切片、数组、映射、字符串、通道
  • 循环控制:break、continue、标签控制
  • 实际应用:数据统计、素数生成、文本分析
  • 性能优化:循环优化技巧和最佳实践

Go 语言的 for 循环功能强大且灵活,配合 range 关键字可以优雅地处理各种数据结构的遍历。


接下来,我们将学习 Go 语言函数,了解如何组织和重用代码。

循环使用建议

  • 优先使用 range 循环遍历数据结构
  • 避免在循环中进行重复的复杂计算
  • 合理使用 break 和 continue 控制循环流程
  • 注意嵌套循环的性能影响

本站内容仅供学习和研究使用。