跳转到内容

Go 循环

来自代码酷

Go循环[编辑 | 编辑源代码]

循环是编程中控制程序流程的重要结构,它允许我们重复执行一段代码,直到满足特定条件。在Go语言中,循环主要通过`for`关键字实现。Go语言的设计哲学强调简洁性,因此它没有像其他语言(如C或Java)那样提供`while`或`do-while`循环,而是通过`for`的不同形式来实现所有循环需求。

基本语法[编辑 | 编辑源代码]

Go语言中的`for`循环有三种主要形式:

1. 传统for循环:类似于C语言中的`for`循环,包含初始化、条件和后置语句。 2. while-like循环:仅包含条件,类似于其他语言的`while`循环。 3. 无限循环:不包含任何条件,会一直执行,直到使用`break`语句退出。

传统for循环[编辑 | 编辑源代码]

语法:

for 初始化语句; 条件表达式; 后置语句 {
    // 循环体
}

示例:

package main

import "fmt"

func main() {
    // 打印数字1到5
    for i := 1; i <= 5; i++ {
        fmt.Println(i)
    }
}

输出:

1
2
3
4
5

while-like循环[编辑 | 编辑源代码]

语法:

for 条件表达式 {
    // 循环体
}

示例:

package main

import "fmt"

func main() {
    // 模拟while循环
    count := 1
    for count <= 5 {
        fmt.Println(count)
        count++
    }
}

输出与上例相同。

无限循环[编辑 | 编辑源代码]

语法:

for {
    // 循环体
    // 通常包含break条件
}

示例:

package main

import "fmt"

func main() {
    // 无限循环,直到count大于5
    count := 1
    for {
        if count > 5 {
            break
        }
        fmt.Println(count)
        count++
    }
}

输出与上例相同。

循环控制语句[编辑 | 编辑源代码]

Go语言提供了几种控制循环执行的语句:

1. break:立即终止循环 2. continue:跳过当前迭代,继续下一次循环 3. goto(不推荐):跳转到指定标签

break示例[编辑 | 编辑源代码]

package main

import "fmt"

func main() {
    for i := 1; i <= 10; i++ {
        if i == 6 {
            break // 当i等于6时退出循环
        }
        fmt.Println(i)
    }
}

输出:

1
2
3
4
5

continue示例[编辑 | 编辑源代码]

package main

import "fmt"

func main() {
    for i := 1; i <= 5; i++ {
        if i == 3 {
            continue // 跳过3的打印
        }
        fmt.Println(i)
    }
}

输出:

1
2
4
5

range循环[编辑 | 编辑源代码]

Go语言提供了`range`关键字,用于遍历数组、切片、字符串、map或通道。这是Go语言中非常强大且常用的循环形式。

语法:

for 索引,  := range 集合 {
    // 循环体
}

遍历切片[编辑 | 编辑源代码]

package main

import "fmt"

func main() {
    fruits := []string{"apple", "banana", "orange"}
    
    for index, fruit := range fruits {
        fmt.Printf("Index: %d, Fruit: %s\n", index, fruit)
    }
}

输出:

Index: 0, Fruit: apple
Index: 1, Fruit: banana
Index: 2, Fruit: orange

遍历map[编辑 | 编辑源代码]

package main

import "fmt"

func main() {
    capitals := map[string]string{
        "USA": "Washington D.C.",
        "Japan": "Tokyo",
        "France": "Paris",
    }
    
    for country, capital := range capitals {
        fmt.Printf("%s's capital is %s\n", country, capital)
    }
}

可能的输出(map遍历顺序是随机的):

USA's capital is Washington D.C.
Japan's capital is Tokyo
France's capital is Paris

嵌套循环[编辑 | 编辑源代码]

Go语言支持循环嵌套,即在一个循环内部包含另一个循环。

示例:

package main

import "fmt"

func main() {
    // 打印乘法表
    for i := 1; i <= 9; i++ {
        for j := 1; j <= i; j++ {
            fmt.Printf("%d*%d=%d\t", j, i, i*j)
        }
        fmt.Println()
    }
}

输出:

1*1=1	
1*2=2	2*2=4	
1*3=3	2*3=6	3*3=9	
...
1*9=9	2*9=18	3*9=27	...	9*9=81

性能考虑[编辑 | 编辑源代码]

在编写循环时,需要注意以下几点性能优化:

1. 尽量减少循环内部的计算量 2. 预先计算循环边界条件 3. 避免在循环内部频繁分配内存 4. 对于大数据集,考虑使用并发处理

示例优化:

package main

import "fmt"

func main() {
    // 非优化版本
    for i := 0; i < len(someLargeSlice); i++ {
        // 每次循环都计算len(someLargeSlice)
    }
    
    // 优化版本
    length := len(someLargeSlice)
    for i := 0; i < length; i++ {
        // 预先计算长度
    }
}

实际应用案例[编辑 | 编辑源代码]

案例1:数据处理[编辑 | 编辑源代码]

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    // 生成随机数切片
    numbers := make([]int, 10)
    for i := range numbers {
        numbers[i] = rand.Intn(100)
    }
    
    // 计算平均值
    sum := 0
    for _, num := range numbers {
        sum += num
    }
    average := float64(sum) / float64(len(numbers))
    
    fmt.Printf("Numbers: %v\nAverage: %.2f\n", numbers, average)
}

案例2:Web请求重试机制[编辑 | 编辑源代码]

package main

import (
    "fmt"
    "net/http"
    "time"
)

func makeRequest(url string, maxRetries int) (*http.Response, error) {
    var resp *http.Response
    var err error
    
    for i := 0; i < maxRetries; i++ {
        resp, err = http.Get(url)
        if err == nil && resp.StatusCode == http.StatusOK {
            return resp, nil
        }
        
        if resp != nil {
            resp.Body.Close()
        }
        
        time.Sleep(time.Second * time.Duration(i+1)) // 指数退避
    }
    
    return nil, fmt.Errorf("after %d retries: %v", maxRetries, err)
}

循环流程图[编辑 | 编辑源代码]

以下是传统for循环的流程图表示:

graph TD A[开始] --> B[初始化] B --> C{条件检查} C -- 真 --> D[执行循环体] D --> E[后置语句] E --> C C -- 假 --> F[结束]

数学表示[编辑 | 编辑源代码]

循环的执行次数可以用数学公式表示。对于一个从i=a开始,到i<b结束,步长为s的循环:

循环次数=bas+1

其中表示向下取整函数。

常见错误与陷阱[编辑 | 编辑源代码]

1. 无限循环:忘记更新循环变量可能导致无限循环

   for i := 0; i < 10; {
       // 忘记i++
   }

2. 作用域问题:循环变量在每次迭代中会被重用

   var funcs []func()
   for i := 0; i < 3; i++ {
       funcs = append(funcs, func() { fmt.Println(i) })
   }
   for _, f := range funcs {
       f() // 全部输出3,而不是0,1,2
   }
  解决方法:
   for i := 0; i < 3; i++ {
       i := i // 创建新的变量副本
       funcs = append(funcs, func() { fmt.Println(i) })
   }

3. 修改range迭代的集合:在range循环中修改集合可能导致意外行为

   nums := []int{1, 2, 3}
   for i, num := range nums {
       nums[i] = num * 2 // 安全
       nums = append(nums, num) // 不安全,可能导致无限循环
   }

总结[编辑 | 编辑源代码]

Go语言的循环结构虽然形式简单(只有`for`关键字),但功能强大且灵活。通过掌握不同的`for`循环形式、循环控制语句和`range`关键字,可以高效地处理各种迭代需求。在实际编程中,应根据具体场景选择合适的循环形式,并注意避免常见的循环陷阱。