# 循环/For
在 Go 中循环只有一种形式,就是For。
# 语法格式
for 循环语句中包含 3 个部分,初始化语句,条件判断语句和循环标记语句
初始化语句在进入 for 循环体前执行,用于初始化循环用的变量,只执行一次
条件判断语句在每轮循环开始前执行,当条件成立时才会继续执行循环体中的内容,否则跳出循环
循环结尾语句在每轮循环的结尾执行,主要用于为条件判断语句中的变量进行赋值
for 初始化语句;条件判断语句;循环结尾语句 {
...
}
for i := 0;i<10;i++{
// ...
}
# 省略写法
开发时,for 循环中除了条件判断语法,其他部分是可以省略的。
// 省略循环结尾部分
for i := 0;i<10{
i++;
}
// 省略初始部分
i:=0
for ;i<10;i++{
// ...
}
// 只保留判断部分
i:= 0
for ;i<10;{
//..
}
记住,但我们使用省略写法时,一定要保留;号,否则 Go 是无法区分他们的。但存在一个情况,是可以省略;的。就是只保留判断部分时。
// 只保留判断部分
i:= 0
for i<10{
//..
}
# white 循环
由于 Go 中只有for一种循环方式,当我们想要实现white时,只要利用for就可以了。
// 相当于white
for {
}
// 效果同上
for true{
}
// 效果同上
for ;;{
}
虽然上面三种方式都能实现white的效果,但一般还是推荐第一种。
# range 关键字
如果我们想要遍历一个切片,最直观的方式应该是:
func main() {
s1 := []string{"mike", "lili", "mary", "tony", "lucy"}
length := len(s1)
for i := 0; i < length; i++ {
fmt.Println(s1[i])
}
}
但如果每次都这样遍历切片就太麻烦了。为此,Go 为我们提供了 range 关键字。使用它我们可以快速遍历一个切片
func main() {
s1 := []string{"mike", "lili", "mary", "tony", "lucy"}
// i 是切片项的索引,v是项的值。
for i,v := range s1 {
fmt.Println(i,v)
}
}
# 遍历切片
利用range我们已经可以很好地遍历切片了。我们甚至可以省略部分内容:
// 不需要索引
for _,v := range s1{
}
// 不需要值
for i := range s1{
}
// 都不需要
for range s1{
}
# 遍历字符
var s = "hello"
for i,v := range s{
fmt.Println(i,v)
}
输出结果:
0 h
1 e
2 l
3 l
4 o
可以看到,当遍历字符时,v会得到一个Unicode字符,i则是该字符的序列。
# 遍历字典
遍历字典的方式与遍历切片相似,但字典中没用序号,有的是key值。
var m := map[string]int{
"tom":18,
"john":20
}
for k,v:= range m{
Println(k,v)
}
输出结果
tom 18
john 20
变量map时,我们可以拿到字典每项的key和value值。
# 遍历信道
除了上面常见的类型遍历,range还可以与信道(channel)配合使用。
var c = make(channel int)
for v:= range c{
// ...
}
这样需要注意,每次遍历时,for循环会从信道中取一项进行。当信道中没有数据时,遍历会阻塞,但不会停止。只有当channel关闭之后,循环才会真正结束。
# 主动退出遍历
那么我们是不是只能等到判断条件为false时,才能结束循环呢?当然不是,Go 为我们提供了一些关键语句,可以让我们主动停止/跳出循环。
# continue语句
cotinue的作用是提前跳出当前这一次的循环,进入下一次循环。
var sum := int
var sl = []int{1,2,3,4,5,6}
for i:= 0; i<len(sl);i++{
if sl[i]%2 == 0 {
// 如果项是偶数就跳出
continue
}
sum += sl[i]
}
Println(sum)
输出结果为切片中奇数的和,偶数被忽略了。
9
# 带label的continue
Go 中continue增加了对 label 的支持。label可以标记跳转目标,通常用于循环嵌套时,可以指定跳出的是哪一层的循环。
var sl = [][]int{
{1,34,26,35,78},
{3,45,13,24,99},
{101,13,38,7,127},
{54,27,40,83,81},
}
//给外层循环打label
outerloop:
for i:=0;i<len(sl);i++{
for j:=0;j<len(sl[i]);j++ {
if sl[i][j]==13 {
fmt.Printf("found13at[%d,%d]\n",i,j)
// 跳出我们标记的label对应的循环
continue outerloop
}
}
}
上方例子中,假如不使用label,执行continue时,默认会跳出最里层的循环。而通过 label 我们可以精确地跳出外层循环。
# break 语句
continue的作用是跳出当前循环中的某一次循环执行,但如果我们想结束整个循环时,就需要用到 break 。
var sl=[]int{5,19,6,3,8,12}
var firstEven int=-1
//找出整型切片sl中的第一个偶数
for i:=0;i<len(sl);i++ {
if sl[i]%2==0 {
firstEven=sl[i]
break
}
}
println(firstEven)
输出结果,这里的代码当遍历到6时,后续的遍历是不会再进行的,此时循环已经结束了。
6
# 带 label 的 break 语句
与continue一样,break也支持label
var sl=[][]int {
{1,34,26,35,78},
{3,45,13,24,99},
{101,13,38,7,127},
{54,27,40,83,81},
}
outerloop:
for i:=0;i<len(sl);i++{
for j:=0;j<len(sl[i]);j++{
if sl[i][j]==gold{
fmt.Printf("foundgoldat[%d,%d]\n",i,j)
break outerloop
}
}
}
← 条件控制/Switch 方法/Method →