在 Go 中唯一的循环语法是for
,然而,它也担任了一些语言中while
的功能,并可搭配range
来使用。
有分号的 for
for
最基本的使用形式,与 C/C++、Java 等语言类似,具有初始化化、条件式、后置式三个部份,中间使用分号加以区隔,不必使用()
括号包住这三个式子,同样地,for
循环本体一定要使用{}
。
初始化化只执行一次,通常用来定义或初始化变量,若是定义变量,可见范围仅在for
中。第一个分号后是每次执行循环本体前会执行一次,且必须是true
或false
的结果,true
就会执行循环本体,false
就会结束循环,第二个分号后,则是每次执行完循环本体后会执行一次。
实际来看个for
循环范例,在文本模式下从 1 显示到 10:
package main
import "fmt"
func main() {
for i := 1; i <= 10; i++ {
fmt.Println(i)
}
}
这个程序白话读来,就是从i
等于 1,只要i
小于等于 10 就执行循环本体(显示i
),然后递增i
。在介绍for
循环时,许多书籍或文件很喜欢用的范例就是显示九九乘法表,这边也用这个例子来示范嵌套循环:
package main
import "fmt"
func main() {
for i, j := 0, 0; i < 10; i, j = i+1, j+1 {
fmt.Printf("%d * %d = %2d\n", i, j, i*j)
}
}
for
中的各陈述是以分号区隔,若当中想写两个陈述则使用逗号区隔,例如:
package main
import "fmt"
func main() {
for i, j := 0, 0; i < 10; i, j = i+1, j+1 {
fmt.Printf("%d * %d = %2d\n", i, j, i*j)
}
}
初始化化、后置式都可以省略,不过,分号必须保留,例如:
package main
import "fmt"
func foo(i int) {
for ; i < 10; i++ {
fmt.Println(i)
}
}
func multiplication_table() {
for i, j := 2, 1; j < 10; {
fmt.Printf("%d * %d = %2d ", i, j, i*j)
if i == 9 {
fmt.Println()
j++
i = (j+1)/j + 1
} else {
i++
}
}
}
func main() {
foo(1)
multiplication_table()
}
无分号的 for
在没有初始化化、后置式,只有条件式的情况,也就是for ; cond;
的时候,可以只写for cond
,这就是 C/C++、Java 中while
循环的作用了:
package main
import "fmt"
func main() {
i := 1
for i < 10 {
fmt.Println(i)
i++
}
}
如果想制造个无穷循环,在 C/C++、Java 等语言中常见写成for(;;)
,在 Go 中是也可以写for ;;
,因为条件式不写默认就是true
,不过,可以只写个for
就可以了,底下是个很无聊的游戏,看谁可以最久不撞到这个数字 5:
package main
import (
"fmt"
"math/rand"
"time"
)
func random(min, max int) int {
rand.Seed(time.Now().Unix())
return rand.Intn(max-min) + min
}
func main() {
for {
number := random(1, 10)
fmt.Println(number)
if number == 5 {
break
}
time.Sleep(time.Second)
}
fmt.Println("I hit 5....Orz")
}
在for
循环中如果执行到break
,会离开循环本体。
for range
Go 的for
可以搭配range
,对 slice、数组、string
、map
和 channel(之后说明)进行迭代,range
视给定的形态不同,会有不同的返回值。
对于 slice、数组、string
、map
,在之前的〈字节构成的字符串〉、〈身为复合值的数组〉、〈底层为数组的 slice〉与〈成对键值的 map〉中,都有相关范例示范,这边不再赘述。