1. for 循环格式
Go
语言仅支持一种循环语句即for
循环,它有 3 种形式,只有其中的一种使用分号。
和 C 语言的 for 一样
for init; condition; post {}
init
: 一般为赋值表达式,给控制变量赋初值,初始语句是在第一次循环前执行的语句,一般使用初始语句执行变量初始化,如果变量在此处被声明,其作用域将被局限在这个for
的范围内。
condition
: 关系表达式或逻辑表达式,循环控制条件,每次循环开始前都会计算条件表达式,如果表达式为true
,则循环继续,否则结束循环,条件表达式可以被忽略,忽略条件表达式后默认形成无限循环。
post
: 一般为赋值表达式,给控制变量增量或减量;
可以看到比较大的一个不同在于for
后面的条件表达式不需要用圆括号()
括起来。左花括号{
必须与for
处于同一行。
Go
语言中的for
循环与C
语言一样,都允许在循环条件中定义和初始化变量,唯一的区别是,Go
语言不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量。
示例-1:
var i intfor ; ; i++ {if i > 10 {break}}
和C
的while
一样
for condition {}
示例-2
var i intfor i <= 10 {i++}
和C
的for(;;)
一样,无限循环
for {}
示例-3
var i intfor {if i > 10 {break}i++}
2. for 循环示例
package mainimport "fmt"func main() {var b int = 15var a intnumbers := [6]int{1, 2, 3, 5} /* for 循环 */for a := 0; a < 10; a++ {// 左花括号{必须与 for 处于同一行fmt.Printf("a 的值为: %d\n", a)}for a < b {a++fmt.Printf("a 的值为: %d\n", a)}for i, x:= range numbers {fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)} }
3. 嵌套 for 循环
package mainimport "fmt"func main() {/* 定义局部变量 */var i, j intfor i=2; i < 100; i++ {for j=2; j <= (i/j); j++ {if(i%j==0) {break; // 如果发现因子,则不是素数}}if(j > (i/j)) {fmt.Printf("%d 是素数\n", i);}} }
4. for 循环应用
Go
语言中range
关键字用于for
循环中迭代数组 (array
)、切片(slice
)、通道(channel
)或集合 (map
) 的元素。通过for range
遍历的返回值有一定的规律:
数组、切片、字符串返回索引和值。map
返回键和值。通道(channel
)只返回通道内的值。
4.1 访问数组
for index , value :=range arry{}for index := range arry{}for _, value :=range arry{}
在上面的例子中将 key 变成了下划线_
,这里的下划线就是匿名变量。
可以理解为一种占位符匿名变量本身不会进行空间分配,也不会占用一个变量的名字在for range
可以对key
使用匿名变量,也可以对value
使用匿名变量
package mainimport "fmt"func main() {array := [3]int{10, 20, 30}for i, v := range array {fmt.Printf("index is %v, value is %v\n", i, v)}for _, v := range array {fmt.Printf("value is %v\n", v)}for i := range array {fmt.Printf("index is %v\n", i)}}
输出:
index is 0, value is 10index is 1, value is 20index is 2, value is 30value is 10value is 20value is 30index is 0index is 1index is 2
4.2 访问切片
for index, value :=range slice{}for index := range slice{}for _, value :=range slice{}
代码演示和数组类似,只需要做如下改动:
array := [3]int{10, 20, 30} // 数组array := []int{10, 20, 30}// 切片
4.3 访问字典
对于map
类型来说,for range 遍历时,key
和value
分别代表map
的索引键key
和索引对应的值,一般被称为map
的键值对,因为它们是一对一对出现的。
for key , value := range map{}for key := range map {}
4.4 访问字符串
range
也可以用来枚举Unicode
字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
for index, value := range stringfor index := range string
示例:
package mainimport "fmt"func main() {s := "hello"for i := range s {fmt.Printf("value is %v\n", s[i])}}
4.5 访问通道
for range
可以遍历通道(channel
),但是通道在遍历时,只输出一个值,即管道内的类型对应的数据。
for value :=range channel{}
代码示例:
c := make(chan int)go func() {c <- 1c <- 2c <- 3close(c)}()for v := range c {fmt.Println(v)}
4. 循环控制语句
4.1 goto
goto
语句用于函数的内部的跳转,需要配合标签一起使用, 具体的格式如下:
goto Lable
goto Lable
的语义是跳转到标签名后的语句处执行,goto
语句有以下几个特点:
goto
语句只能在函数内跳转;goto
语句不能跳过内部变量声明语句,这些变量在goto
语句的标签语句处又是可见的;
goto L // BAD ,跳过v := 3 这条语句是不允许的v := 3L :
goto
语句只能跳到同级作用域或者上层作用域内,不能跳到内部作用域内;
if n%2 == 1 {goto LL}for n > 0 {f()n-- LL:f()n--}
代码示例:
package mainimport "fmt"func main() {for x := 0; x < 10; x++ {for y := 0; y < 10; y++ {if y == 2 {// 跳转到标签goto breakHere}}}// 手动返回, 避免执行进入标签return// 标签breakHere:fmt.Println("done")}
4.2 continue
跳过当前循环的剩余语句,仅能用于continue
语句,然后继续进行下一轮循环,有两种格式:
单独使用,用于跳出continue
当前所在的for
循环的本次迭代;
和标签一起使用,用于跳出标签所标识的for
语句的本次选代,但标签和continue
必须在同一个函数内。
例如:
package mainimport "fmt"func main() {OuterLoop:for i := 0; i < 2; i++ {for j := 0; j < 5; j++ {switch j {case 2:fmt.Println(i, j)continue OuterLoop}}}}
4.3 break
break
用于函数内跳出for
、switch
、select
语句的执行,有两种使用格式:
单独使用,用于跳出break
当前所在的for
、switch
、select
语句的执行;
和标签一起使用,用于跳出标签所标识的for
、switch
、select
语句的执行,可用于跳出多重循环,但标签和break
必须在同一个函数内。
例如:
package mainimport "fmt"func main() {Ll:for i := 0; ; i++ {for j := 0; ; j++ {if i >= 5 {// 跳到 Ll 标签所在的 for 循环 i++ 处执行fmt.Println(i)break Ll//the following is not executed}if j > 10 {fmt.Println(j)// 默认仅跳到离 break 最近的内层循环 j++ 处执行break}}}}
不带label
的break
语句中断执行并跳出的,是同一函数内break
语句所在的最内层的for
、switch
或select
。
func main() {var sl = []int{5, 19, 6, 3, 8, 12}var firstEven int = -1// find first even number of the interger sliceloop:for i := 0; i < len(sl); i++ {switch sl[i] % 2 {case 0:firstEven = sl[i]break loopcase 1:// do nothing}}println(firstEven) // 6}
我们定义了一个 label:loop
,这个label
附在for
循环的外面,指代for
循环的执行。当代码执行到break loop
时,程序将停止label loop
所指代的for
循环的执行。