# 循环语句

循环语句用来重复执行一个代码块。

跟其他编程语言不同，Golang保持一种宁缺毋滥的态度，仅支持`for`语句循环，不支持`while`语句，后面我们会看到`for`语句完全能满足所有循环场景，因此也就不需要再多一种`while`循环语句了。

#### for循环语法

for循环语法如下：

```go
for initialization; condition; post {

}
```

其中初始化语句`initialization`仅执行一次。初始化语句执行完之后判断`condition`条件，如果条件成立，则执行大括号中的循环体代码块，仅接着执行`post`语句。`post`语句执行完之后会再次判断`condition`是否成立，如果仍然成立，那么继续再执行循环体代码块。该过程会循环不停的执行下去，直到`condition`条件不再成立为止。

`for`语句中的三个组成部分`initialization`、`condition`以及`post`都是非必须的。下面我们通过例子来更好的理解Golang中的`for`循环。

#### 例子

我们使用`for`循环来打印数字1到10。

```go
package main

import "fmt"

func main() {
    for i:= 1; i <= 10; i++ {
        fmt.Printf("%d ", i)
    }
}
```

[Go Playground在线运行](https://play.golang.org/p/MDaUaon5zqS) 这段程序中，变量`i`初始化为1。`for`循环的条件是判断`i <= 10`是否成立，如果成立，会打印出变量`i`的值，否则停止循环的执行，每次循环体执行后都是执行`i++`语句，将变量`i`加1，最终变量`i`会大于10，退出循环。

这段程序执行结果为：`1 2 3 4 5 6 7 8 9 10`。 `for`循环声明的变量`i`仅在`for`循环内部可见，无法在`for`循环外访问。

#### break

`break`语句用来强制退出`for`循环，然后接着执行`for`循环后面的代码。

现在我们通过使用`break`语句来打印数字1到5。

```go
package main

import "fmt"

func main() {  
    for i := 1; i <= 10; i++ {
        if i > 5 {
            break //loop is terminated if i > 5
        }
        fmt.Printf("%d ", i)
    }
    fmt.Printf("\nline after for loop")
}
```

[Go Playground在线运行](https://play.golang.org/p/3tbD60Xix95)

这段代码中的循环体每次执行时都会检查变量`i`的值，如果该值大于5，就会通过`break`语句强制终止循环的执行。然后执行仅接着`for`循环的代码。这段代码输出如下：

```
1 2 3 4 5 
line after for loop
```

#### continue

`continue`语句用来跳过当前循环体的执行，循环体内`continue`后面的语句都会被跳过，然后进入下一个迭代的执行。

下面我们利用`continue`语句来实现一个程序来打印1到10之间的偶数。

```go
package main

import "fmt"

func main() {  
    for i := 1; i <= 10; i++ {
        if i % 2 == 0 {
            continue
        }
        fmt.Printf("%d ", i)
    }
}
```

[Go Playground在线运行](https://play.golang.org/p/mn2WndDxtSj) 这段程序中通过`i % 2 == 0`来判断`i`是否是偶数，如果条件成立，那么执行`continue`语句，因此会跳过后面的打印语句，进入下一次迭代。该程序输出如下：`1 3 5 7 9`。

#### 嵌套for循环

一个`for`循环可以嵌套在另一个`for`循环执行。 我们实现一个程序打印下面所示的图案：

```
*
**
***
****
*****
```

下面的程序使用嵌套循环来打印上述图案。

```go
package main

import "fmt"

func main() {  
    n := 5
    for i := 0; i < n; i++ {
        for j := 0; j <= i; j++ {
            fmt.Print("*")
        }
        fmt.Println()
    }
}
```

[Go Playground在线运行](https://play.golang.org/p/fOl9h0UyQBW) 该程序中变量`n`表示行数。外层`for`循环中，变量`i`从0开始循环到4，共5次。内层`for`循环中，变量`j`从0开始循环到`i`。内层`for`循环每次执行打印符号`*`，外层`for`循环在每次内层`for`循环执行完之后打印一个换行，然后开始新的一行。

#### 标签

我们知道，可以通过`break`语句来退出当前`for`循环，注意这里退出的是当前循环。那么如果想在内层`for`循环退出外出`for`循环怎么做到呢？Golang中我们可以通过标签来实现。

我们先看一下下面这个例子：

```go
package main

import "fmt"

func main() {  
    for i := 0; i < 3; i++ {
        for j := 1; j < 4; j++ {
            fmt.Printf("i = %d , j = %d\n", i, j)
        }

    }
}
```

[Go Playground在线运行](https://play.golang.org/p/77fyT1MrU7I) 这个程序没什么特别的，就是个循环嵌套而已，输出如下：

```
i = 0 , j = 1
i = 0 , j = 2
i = 0 , j = 3
i = 1 , j = 1
i = 1 , j = 2
i = 1 , j = 3
i = 2 , j = 1
i = 2 , j = 2
i = 2 , j = 3
```

假如我们想在变量`i`和`j`的值相同时停止打印，即同时停止内、外层循环怎么实现呢？我们先尝试在内层循环增加`break`语句看下效果：

```go
package main

import "fmt"

func main() {  
    for i := 0; i < 3; i++ {
        for j := 1; j < 4; j++ {
            fmt.Printf("i = %d , j = %d\n", i, j)
            if i == j {
                break
            }
        }

    }
}
```

[Go Playground在线运行](https://play.golang.org/p/KNUFXaRoDgr) 跟我们想的一样，`break`仅能退出当前循环，无法退出双层循环，现在输出如下：

```
i = 0 , j = 1
i = 0 , j = 2
i = 0 , j = 3
i = 1 , j = 1
i = 2 , j = 1
i = 2 , j = 2
```

当然，如果可以在外层循环体也加个判断，然后使用`break`退出外层循环：

```go
package main

import "fmt"

func main() {  
    for i := 0; i < 3; i++ {
        j := 1
        for ; j < 4; j++ {
            fmt.Printf("i = %d , j = %d\n", i, j)
            if i == j {
                break
            }
        }
    if i == j {
            break
    }
    }
}
```

[Go Playground在线运行](https://play.golang.org/p/xhDOOBHvkbz) 现在可以输出我们想要的结果了：

```
i = 0 , j = 1
i = 0 , j = 2
i = 0 , j = 3
i = 1 , j = 1
```

这种方式固然能满足我们的要求，但是这里内外循环都做了判断，显得繁琐，借助**标签**我们可以更加优雅的实现这个功能：

```go
package main

import "fmt"

func main() {  
outer:  
    for i := 0; i < 3; i++ {
        for j := 1; j < 4; j++ {
            fmt.Printf("i = %d , j = %d\n", i, j)
            if i == j {
                break outer
            }
        }

    }
}
```

[Go Playground在线运行](https://play.golang.org/p/rW1fRZU_06f) 这里我们给外层循环加了个标签`outer`，在内层循环体内，我们通过`break outer`指定要退出的循环标签名称，来直接了当的退出外层循环，输出如下：

```
i = 0 , j = 1
i = 0 , j = 2
i = 0 , j = 3
i = 1 , j = 1
```

#### 更多例子

现在我们多实现几个例子来试用下`for`循环的各种其他用法。 下面的程序打印出0到10之间的偶数。

```go
package main

import "fmt"

func main() {  
    i := 0
    for ;i <= 10; { // initialisation and post are omitted
        fmt.Printf("%d ", i)
        i += 2
    }
}
```

[Go Playground在线运行](https://play.golang.org/p/CFlKZ8A_j3l) 前面我们已经提到过，`for`语句中的三个组成部分`initialization`(循环变量初始化)、`condition`(条件判断)以及`post`(循环收尾语句)都是非必须的。这个例子中的`for`语句就不包含`initialization`(循环变量初始化)和`post`(循环收尾语句)。这里循环变量`i`的初始化在`for`循环外就完成了，而且循环变量`i`的递增是在循环体内执行的。该程序输出：`0 2 4 6 8 10`。

上面程序中`for`语句中的分号`;`可以省略，写法如下：

```go
package main

import "fmt"

func main() {  
    i := 0
    for i <= 10 { // initialisation and post are omitted
        fmt.Printf("%d ", i)
        i += 2
    }
}
```

[Go Playground在线运行](https://play.golang.org/p/nBkzD_s4LF1) 细心就会发现，这不就是while循环的写法么？对！因此Golang中实现循环有`for`语句一种就够了。

我们可以在`for`语句中同时使用多个变量，比如下面的程序：

```go
package main

import "fmt"

func main() {  
    for no, i := 10, 1; i <= 10 && no <= 19; i, no = i + 1, no + 1 { //multiple initialisation and increment
        fmt.Printf("%d * %d = %d\n", no, i, no * i)
    }

}
```

[Go Playground在线运行](https://play.golang.org/p/llnYTxoDDTo) 这里在`for`语句中同时初始化了两个变量`no`和`i`，每次循环体执行结束后两个变量均加1。循环体执行的判断条件同时基于这两个变量来判断。该程序执行结果如下：

```go
10 * 1 = 10
11 * 2 = 22
12 * 3 = 36
13 * 4 = 52
14 * 5 = 70
15 * 6 = 90
16 * 7 = 112
17 * 8 = 136
18 * 9 = 162
19 * 10 = 190
```

#### 无限循环

创建无限循环的语句如下：

```go
for {

}
```

下面的程序会无限打印`Hello World`。

```go
package main

import "fmt"

func main() {  
    for {
        fmt.Println("Hello World")
    }
}
```

Golang中提供了一种非常方便的迭代数组的`for`循环方式，需要借助`range`，这个后面我们讲到数组时再详细讨论。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sunwenfei.gitbook.io/sunwenfei/golang/golang-ji-chu-jiao-cheng/tiao-jian-xun-huan/xun-huan-yu-ju.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
