Go 学习笔记(9)— 循环(for、for range访问数组、切片、字符串和通道、goto、continue、break)

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 int

for ; ; i++ {

    if i > 10 {
        break
    }
}
  • Cwhile 一样
for condition { }

示例-2

var i int
for i <= 10 {
    i++
}
  • Cfor(;;) 一样,无限循环
for { }

示例-3

var i int

for {
    if i > 10 {
        break
    }
    i++
}

2. for 循环示例

package main

import "fmt"

func main() {

   var b int = 15
   var a int

   numbers := [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 main

import "fmt"

func main() {
   /* 定义局部变量 */
   var i, j int

   for 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 main

import "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 10
index is 1, value is 20
index is 2, value is 30
value is 10
value is 20
value is 30
index is 0
index is 1
index 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 遍历时, keyvalue 分别代表 map 的索引键 key 和索引对应的值,一般被称为 map 的键值对,因为它们是一对一对出现的。

for key , value := range map{}
for key := range map {}

4.4 访问字符串

range 也可以用来枚举 Unicode 字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。

for index, value := range string
for index := range string

示例:

package main

import "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 <- 1
    c <- 2
    c <- 3
    close(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 := 3
L :
  • goto 语句只能跳到同级作用域或者上层作用域内,不能跳到内部作用域内;
if n%2 == 1 {
    goto LL
}
for n > 0 {
    f()
    n-- 
LL:
    f()
    n--
}

代码示例:

package main

import "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 main

import "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 用于函数内跳出 forswitchselect 语句的执行,有两种使用格式:

  • 单独使用,用于跳出 break 当前所在的 forswitchselect 语句的执行;

  • 和标签一起使用,用于跳出标签所标识的 forswitchselect 语句的执行,可用于跳出多重循环,但标签和 break 必须在同一个函数内。

例如:

package main

import "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
			}
		}
	}

}

不带 labelbreak 语句中断执行并跳出的,是同一函数内 break 语句所在的最内层的 forswitchselect

func main() {
    var sl = []int{5, 19, 6, 3, 8, 12}
    var firstEven int = -1

    // find first even number of the interger slice
loop:
    for i := 0; i < len(sl); i++ {
        switch sl[i] % 2 {
        case 0:
            firstEven = sl[i]
            break loop
        case 1:
            // do nothing
        }
    }
    println(firstEven) // 6
}

我们定义了一个 label:loop,这个 label 附在 for 循环的外面,指代 for 循环的执行。当代码执行到break loop 时,程序将停止 label loop 所指代的 for 循环的执行。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值