Go语言详解 第3章. 流程控制

1.条件语句(if)

Go 语言条件语句: 条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句。

Go 语言提供了以下几种条件判断语句:

if 语句

if 语句 由一个布尔表达式后紧跟一个或多个语句组成。

Go 编程语言中 if 语句的语法如下:

  1. 可省略条件表达式括号。
  2. 持初始化语句,可定义代码块局部变量。
  3. 代码块左 括号必须在条件表达式尾部。
  4. if 布尔表达式 {
  5. /* 在布尔表达式为 true 时执行 */
  6. }

if 在布尔表达式为 true 时,其后紧跟的语句块执行,如果为 false 则不执行。

  1. x := 0
  2. // if x > 10 // Error: missing condition in if statement
  3. // {
  4. // }
  5. if n := "abc"; x > 0 { // 初始化语句未必就是定义变量, 如 println("init") 也是可以的。
  6. println(n[2])
  7. } else if x < 0 { // 注意 else if 和 else 左大括号位置。
  8. println(n[1])
  9. } else {
  10. println(n[0])
  11. }

*不支持三元操作符(三目运算符) “a > b ? a : b”。

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 定义局部变量 */
  5. var a int = 10
  6. /* 使用 if 语句判断布尔表达式 */
  7. if a < 20 {
  8. /* 如果条件为 true 则执行以下语句 */
  9. fmt.Printf("a 小于 20\n" )
  10. }
  11. fmt.Printf("a 的值为 : %d\n", a)
  12. }

以上代码执行结果为:

a 小于 20

a 的值为 : 10

if…else 语句

if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。

Go 编程语言中 if…else 语句的语法如下:

  1. if 布尔表达式 {
  2. /* 在布尔表达式为 true 时执行 */
  3. } else {
  4. /* 在布尔表达式为 false 时执行 */
  5. }

if 在布尔表达式为 true 时,其后紧跟的语句块执行,如果为 false 则执行 else 语句块。

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 局部变量定义 */
  5. var a int = 100
  6. /* 判断布尔表达式 */
  7. if a < 20 {
  8. /* 如果条件为 true 则执行以下语句 */
  9. fmt.Printf("a 小于 20\n" )
  10. } else {
  11. /* 如果条件为 false 则执行以下语句 */
  12. fmt.Printf("a 不小于 20\n" )
  13. }
  14. fmt.Printf("a 的值为 : %d\n", a)
  15. }

以上代码执行结果为:

a 不小于 20

a 的值为 : 100

if 嵌套语句

你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。

Go 编程语言中 if…else 语句的语法如下:

  1. if 布尔表达式 1 {
  2. /* 在布尔表达式 1 为 true 时执行 */
  3. if 布尔表达式 2 {
  4. /* 在布尔表达式 2 为 true 时执行 */
  5. }
  6. }

你可以以同样的方式在 if 语句中嵌套 else if…else 语句

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 定义局部变量 */
  5. var a int = 100
  6. var b int = 200
  7. /* 判断条件 */
  8. if a == 100 {
  9. /* if 条件语句为 true 执行 */
  10. if b == 200 {
  11. /* if 条件语句为 true 执行 */
  12. fmt.Printf("a 的值为 100 , b 的值为 200\n" )
  13. }
  14. }
  15. fmt.Printf("a 值为 : %d\n", a )
  16. fmt.Printf("b 值为 : %d\n", b )
  17. }

以上代码执行结果为:

a 的值为 100 , b 的值为 200

a 值为 : 100

b 值为 : 200

2.条件语句 (switch)

switch 语句

用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上直下逐一测试,直到匹配为止。

Golang switch 分支表达式可以是任意类型,不限于常量。可省略 break,默认自动终止。

Go 编程语言中 switch 语句的语法如下:

  1. switch var1 {
  2. case val1:
  3. ...
  4. case val2:
  5. ...
  6. default:
  7. ...
  8. }

变量 var1 可以是任何类型,而 val1 和 val2 则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式。

您可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:case val1, val2, val3。

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 定义局部变量 */
  5. var grade string = "B"
  6. var marks int = 90
  7. switch marks {
  8. case 90: grade = "A"
  9. case 80: grade = "B"
  10. case 50,60,70 : grade = "C"
  11. default: grade = "D"
  12. }
  13. switch {
  14. case grade == "A" :
  15. fmt.Printf("优秀!\n" )
  16. case grade == "B", grade == "C" :
  17. fmt.Printf("良好\n" )
  18. case grade == "D" :
  19. fmt.Printf("及格\n" )
  20. case grade == "F":
  21. fmt.Printf("不及格\n" )
  22. default:
  23. fmt.Printf("差\n" )
  24. }
  25. fmt.Printf("你的等级是 %s\n", grade )
  26. }

以上代码执行结果为:

优秀!

你的等级是 A

Type Switch

switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。

  1. Type Switch 语法格式如下:
  2. switch x.(type){
  3. case type:
  4. statement(s)
  5. case type:
  6. statement(s)
  7. /* 你可以定义任意个数的case */
  8. default: /* 可选 */
  9. statement(s)
  10. }

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var x interface{}
  5. //写法一:
  6. switch i := x.(type) { // 带初始化语句
  7. case nil:
  8. fmt.Printf(" x 的类型 :%T\r\n", i)
  9. case int:
  10. fmt.Printf("x 是 int 型")
  11. case float64:
  12. fmt.Printf("x 是 float64 型")
  13. case func(int) float64:
  14. fmt.Printf("x 是 func(int) 型")
  15. case bool, string:
  16. fmt.Printf("x 是 bool 或 string 型")
  17. default:
  18. fmt.Printf("未知型")
  19. }
  20. //写法二
  21. var j = 0
  22. switch j {
  23. case 0:
  24. case 1:
  25. fmt.Println("1")
  26. case 2:
  27. fmt.Println("2")
  28. default:
  29. fmt.Println("def")
  30. }
  31. //写法三
  32. var k = 0
  33. switch k {
  34. case 0:
  35. println("fallthrough")
  36. fallthrough
  37. /*
  38. Go的switch非常灵活,表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项;
  39. 而如果switch没有表达式,它会匹配true。
  40. Go里面switch默认相当于每个case最后带有break,
  41. 匹配成功后不会自动向下执行其他case,而是跳出整个switch,
  42. 但是可以使用fallthrough强制执行后面的case代码。
  43. */
  44. case 1:
  45. fmt.Println("1")
  46. case 2:
  47. fmt.Println("2")
  48. default:
  49. fmt.Println("def")
  50. }
  51. //写法三
  52. var m = 0
  53. switch m {
  54. case 0, 1:
  55. fmt.Println("1")
  56. case 2:
  57. fmt.Println("2")
  58. default:
  59. fmt.Println("def")
  60. }
  61. //写法四
  62. var n = 0
  63. switch { //省略条件表达式,可当 if...else if...else
  64. case n > 0 && n < 10:
  65. fmt.Println("i > 0 and i < 10")
  66. case n > 10 && n < 20:
  67. fmt.Println("i > 10 and i < 20")
  68. default:
  69. fmt.Println("def")
  70. }
  71. }

以上代码执行结果为:

x 的类型 :

fallthrough

1

1

def

3.条件语句 (select)

select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

select 是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。

select 随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的。

Go 编程语言中 select 语句的语法如下:

  1. select {
  2. case communication clause :
  3. statement(s);
  4. case communication clause :
  5. statement(s);
  6. /* 你可以定义任意数量的 case */
  7. default : /* 可选 */
  8. statement(s);
  9. }

以下描述了 select 语句的语法:

  1. 每个case都必须是一个通信
  2. 所有channel表达式都会被求值
  3. 所有被发送的表达式都会被求值
  4. 如果任意某个通信可以进行,它就执行;其他被忽略。
  5. 如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行。
  6. 否则:
  7. 如果有default子句,则执行该语句。
  8. 如果没有default字句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值。

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var c1, c2, c3 chan int
  5. var i1, i2 int
  6. select {
  7. case i1 = <-c1:
  8. fmt.Printf("received ", i1, " from c1\n")
  9. case c2 <- i2:
  10. fmt.Printf("sent ", i2, " to c2\n")
  11. case i3, ok := (<-c3): // same as: i3, ok := <-c3
  12. if ok {
  13. fmt.Printf("received ", i3, " from c3\n")
  14. } else {
  15. fmt.Printf("c3 is closed\n")
  16. }
  17. default:
  18. fmt.Printf("no communication\n")
  19. }
  20. }

以上代码执行结果为:

no communication

select可以监听channel的数据流动 select的用法与switch语法非常类似,由select开始的一个新的选择块,每个选择条件由case语句来描述

与switch语句可以选择任何使用相等比较的条件相比,select由比较多的限制,其中最大的一条限制就是每个case语句里必须是一个IO操作。

  1. select { //不停的在这里检测
  2. case <-chanl : //检测有没有数据可以读
  3. //如果chanl成功读取到数据,则进行该case处理语句
  4. case chan2 <- 1 : //检测有没有可以写
  5. //如果成功向chan2写入数据,则进行该case处理语句
  6. //假如没有default,那么在以上两个条件都不成立的情况下,就会在此阻塞//一般default会不写在里面,select中的default子句总是可运行的,因为会很消耗CPU资源
  7. default:
  8. //如果以上都没有符合条件,那么则进行default处理流程
  9. }

在一个select语句中,Go会按顺序从头到尾评估每一个发送和接收的语句。

如果其中的任意一个语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用。

如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有两种可能的情况:

  1. 如果给出了default语句,那么就会执行default的流程,同时程序的执行会从select语句后的语句中恢复。

  2. 如果没有default语句,那么select语句将被阻塞,直到至少有一个case可以进行下去。

Golang select的使用及典型用法

基本使用

select是Go中的一个控制结构,类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。

  • select中的case语句必须是一个channel操作

  • select中的default子句总是可运行的。

  • 如果有多个case都可以运行,select会随机公平地选出一个执行,其他不会执行。

  • 如果没有可运行的case语句,且有default语句,那么就会执行default的动作。

  • 如果没有可运行的case语句,且没有default语句,select将阻塞,直到某个case通信可以运行。

例如:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var c1, c2, c3 chan int
  5. var i1, i2 int
  6. select {
  7. case i1 = <-c1:
  8. fmt.Printf("received ", i1, " from c1\n")
  9. case c2 <- i2:
  10. fmt.Printf("sent ", i2, " to c2\n")
  11. case i3, ok := (<-c3): // same as: i3, ok := <-c3
  12. if ok {
  13. fmt.Printf("received ", i3, " from c3\n")
  14. } else {
  15. fmt.Printf("c3 is closed\n")
  16. }
  17. default:
  18. fmt.Printf("no communication\n")
  19. }
  20. }
  21. //输出:no communication

典型用法

超时判断

  1. //比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行
  2. var resChan = make(chan int)
  3. // do request
  4. func test() {
  5. select {
  6. case data := <-resChan:
  7. doData(data)
  8. case <-time.After(time.Second * 3):
  9. fmt.Println("request time out")
  10. }
  11. }
  12. func doData(data int) {
  13. //...
  14. }

退出

  1. //主线程(协程)中如下:
  2. var shouldQuit=make(chan struct{})
  3. fun main(){
  4. {
  5. //loop
  6. }
  7. //...out of the loop
  8. select {
  9. case <-c.shouldQuit:
  10. cleanUp()
  11. return
  12. default:
  13. }
  14. //...
  15. }
  16. //再另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行
  17. close(shouldQuit)

判断channel是否阻塞

  1. //在某些情况下是存在不希望channel缓存满了的需求的,可以用如下方法判断
  2. ch := make (chan int, 5)
  3. //...
  4. data:=0
  5. select {
  6. case ch <- data:
  7. default:
  8. //做相应操作,比如丢弃data。视需求而定
  9. }

4.循环语句 (for)

Golang for支持三种循环方式,包括类似 while 的语法。

for循环

是一个循环控制结构,可以执行指定次数的循环。

Go语言的For循环有3中形式,只有其中的一种使用分号。

  1. for init; condition; post { }
  2. for condition { }
  3. for { }
  4. init 一般为赋值表达式,给控制变量赋初值;
  5. condition 关系表达式或逻辑表达式,循环控制条件;
  6. post 一般为赋值表达式,给控制变量增量或减量。
  7. for语句执行过程如下:
  8. 1. 先对表达式 init 赋初值;
  9. 2. 判别赋值表达式 init 是否满足给定 condition 条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。
  1. s := "abc"
  2. for i, n := 0, len(s); i < n; i++ { // 常见的 for 循环,支持初始化语句。
  3. println(s[i])
  4. }
  5. n := len(s)
  6. for n > 0 { // 替代 while (n > 0) {}
  7. println(s[n]) // 替代 for (; n > 0;) {}
  8. n--
  9. }
  10. for { // 替代 while (true) {}
  11. println(s) // 替代 for (;;) {}
  12. }

不要期望编译器能理解你的想法,在初始化语句中计算出全部结果是个好主意。

  1. package main
  2. func length(s string) int {
  3. println("call length.")
  4. return len(s)
  5. }
  6. func main() {
  7. s := "abcd"
  8. for i, n := 0, length(s); i < n; i++ { // 避免多次调用 length 函数。
  9. println(i, s[i])
  10. }
  11. }

输出:

call length.

0 97

1 98

2 99

3 100

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var b int = 15
  5. var a int
  6. numbers := [6]int{1, 2, 3, 5}
  7. /* for 循环 */
  8. for a := 0; a < 10; a++ {
  9. fmt.Printf("a 的值为: %d\n", a)
  10. }
  11. for a < b {
  12. a++
  13. fmt.Printf("a 的值为: %d\n", a)
  14. }
  15. for i,x:= range numbers {
  16. fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
  17. }
  18. }

以上实例运行输出结果为:

  1. a 的值为: 0
  2. a 的值为: 1
  3. a 的值为: 2
  4. a 的值为: 3
  5. a 的值为: 4
  6. a 的值为: 5
  7. a 的值为: 6
  8. a 的值为: 7
  9. a 的值为: 8
  10. a 的值为: 9
  11. a 的值为: 1
  12. a 的值为: 2
  13. a 的值为: 3
  14. a 的值为: 4
  15. a 的值为: 5
  16. a 的值为: 6
  17. a 的值为: 7
  18. a 的值为: 8
  19. a 的值为: 9
  20. a 的值为: 10
  21. a 的值为: 11
  22. a 的值为: 12
  23. a 的值为: 13
  24. a 的值为: 14
  25. a 的值为: 15
  26. 0 x 的值 = 1
  27. 1 x 的值 = 2
  28. 2 x 的值 = 3
  29. 3 x 的值 = 5
  30. 4 x 的值 = 0
  31. 5 x 的值 = 0

循环嵌套

在 for 循环中嵌套一个或多个 for 循环

以下为 Go 语言嵌套循环的格式:

  1. for [condition | ( init; condition; increment ) | Range]
  2. {
  3. for [condition | ( init; condition; increment ) | Range]
  4. {
  5. statement(s)
  6. }
  7. statement(s)
  8. }

以下实例使用循环嵌套来输出 2 到 100 间的素数:

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 定义局部变量 */
  5. var i, j int
  6. for i=2; i < 100; i++ {
  7. for j=2; j <= (i/j); j++ {
  8. if(i%j==0) {
  9. break // 如果发现因子,则不是素数
  10. }
  11. }
  12. if(j > (i/j)) {
  13. fmt.Printf("%d 是素数\n", i)
  14. }
  15. }
  16. }

以上实例运行输出结果为:

  1. 2 是素数
  2. 3 是素数
  3. 5 是素数
  4. 7 是素数
  5. 11 是素数
  6. 13 是素数
  7. 17 是素数
  8. 19 是素数
  9. 23 是素数
  10. 29 是素数
  11. 31 是素数
  12. 37 是素数
  13. 41 是素数
  14. 43 是素数
  15. 47 是素数
  16. 53 是素数
  17. 59 是素数
  18. 61 是素数
  19. 67 是素数
  20. 71 是素数
  21. 73 是素数
  22. 79 是素数
  23. 83 是素数
  24. 89 是素数
  25. 97 是素数

无限循环

如过循环中条件语句永远不为 false 则会进行无限循环,我们可以通过 for 循环语句中只设置一个条件表达式来执行无限循环:

  1. package main
  2. import "fmt"
  3. func main() {
  4. for true {
  5. fmt.Printf("这是无限循环。\n");
  6. }
  7. }

5.循环语句 (range)

Golang range类似迭代器操作,返回 (索引, 值) 或 (键, 值)。

for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

  1. for key, value := range oldMap {
  2. newMap[key] = value
  3. }
1st value 2nd value
string index s[index] unicode, rune
array/slice index s[index]
map key m[key]
channel element

可忽略不想要的返回值,或 “_” 这个特殊变量。

  1. package main
  2. func main() {
  3. s := "abc"
  4. // 忽略 2nd value,支持 string/array/slice/map。
  5. for i := range s {
  6. println(s[i])
  7. }
  8. // 忽略 index。
  9. for _, c := range s {
  10. println(c)
  11. }
  12. // 忽略全部返回值,仅迭代。
  13. for range s {
  14. }
  15. m := map[string]int{"a": 1, "b": 2}
  16. // 返回 (key, value)。
  17. for k, v := range m {
  18. println(k, v)
  19. }
  20. }

输出结果:

  1. 97
  2. 98
  3. 99
  4. 97
  5. 98
  6. 99
  7. a 1
  8. b 2

*注意,range 会复制对象。

  1. package main
  2. import "fmt"
  3. func main() {
  4. a := [3]int{0, 1, 2}
  5. for i, v := range a { // index、value 都是从复制品中取出。
  6. if i == 0 { // 在修改前,我们先修改原数组。
  7. a[1], a[2] = 999, 999
  8. fmt.Println(a) // 确认修改有效,输出 [0, 999, 999]。
  9. }
  10. a[i] = v + 100 // 使用复制品中取出的 value 修改原数组。
  11. }
  12. fmt.Println(a) // 输出 [100, 101, 102]。
  13. }

输出结果:

[0 999 999]

[100 101 102]

建议改用引用类型,其底层数据不会被复制。

  1. package main
  2. func main() {
  3. s := []int{1, 2, 3, 4, 5}
  4. for i, v := range s { // 复制 struct slice { pointer, len, cap }。
  5. if i == 0 {
  6. s = s[:3] // 对 slice 的修改,不会影响 range。
  7. s[2] = 100 // 对底层数据的修改。
  8. }
  9. println(i, v)
  10. }
  11. }

输出结果:

  1. 0 1
  2. 1 2
  3. 2 100
  4. 3 4
  5. 4 5

另外两种引用类型 map、channel 是指针包装,而不像 slice 是 struct。

for 和 for range有什么区别?

主要是使用场景不同

for可以

  • 遍历array和slice
  • 遍历key为整型递增的map
  • 遍历string

for range可以完成所有for可以做的事情,却能做到for不能做的,包括

  • 遍历key为string类型的map并同时获取key和value
  • 遍历channel

6.循环控制Goto、Break、Continue

循环控制语句可以控制循环体内语句的执行过程。 GO 语言支持以下几种循环控制语句:

GotoBreakContinue

  1. 三个语句都可以配合标签(label)使用
  2. 标签名区分大小写,定以后若不使用会造成编译错误
  3. continue、break配合标签(label)可用于多层循环跳出
  4. goto是调整执行位置,与continue、break配合标签(label)的结果并不相同

goto 语句

将控制转移到被标记的语句。

Go 语言的 goto 语句可以无条件地转移到过程中指定的行。

goto语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能。

但是,在结构化程序设计中一般不主张使用goto语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。

goto 语法格式如下:

  1. goto label;
  2. ..
  3. .
  4. label: statement;

Golang支持在函数内 goto 跳转。标签名区分大小写,未使用标签引发错误。

  1. func main() {
  2. var i int
  3. for {
  4. println(i)
  5. i++
  6. if i > 2 { goto BREAK }
  7. }
  8. BREAK:
  9. println("break")
  10. EXIT: // Error: label EXIT defined and not used
  11. }

goto 实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 定义局部变量 */
  5. var a int = 10
  6. /* 循环 */
  7. LOOP: for a < 20 {
  8. if a == 15 {
  9. /* 跳过迭代 */
  10. a = a + 1
  11. goto LOOP
  12. }
  13. fmt.Printf("a的值为 : %d\n", a)
  14. a++
  15. }
  16. }

Golang支持在函数内 goto 跳转。goto语句与标签之间不能有变量声明。否则编译错误。

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("start")
  5. goto Loop
  6. var i int = 1
  7. Loop:
  8. fmt.Println(i)
  9. fmt.Println("end")
  10. }

编译错误:

./main.go:7:7: goto Loop jumps over declaration of i at ./main.go:9:6

以上实例执行结果为:

  1. a的值为 : 10
  2. a的值为 : 11
  3. a的值为 : 12
  4. a的值为 : 13
  5. a的值为 : 14
  6. a的值为 : 16
  7. a的值为 : 17
  8. a的值为 : 18
  9. a的值为 : 19

break 语句

经常用于中断当前 for 循环或跳出 switch 语句

Go 语言中 break 语句用于以下两方面:

  1. 用于循环语句中跳出循环,并开始执行循环之后的语句。
  2. break在switch(开关语句)中在执行一条case后跳出语句的作用。

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 定义局部变量 */
  5. var a int = 10
  6. /* for 循环 */
  7. for a < 20 {
  8. fmt.Printf("a 的值为 : %d\n", a)
  9. a++
  10. if a > 15 {
  11. /* 使用 break 语句跳出循环 */
  12. break
  13. }
  14. }
  15. }

以上实例执行结果为:

  1. a 的值为 : 10
  2. a 的值为 : 11
  3. a 的值为 : 12
  4. a 的值为 : 13
  5. a 的值为 : 14
  6. a 的值为 : 15

Break label 语句

我们在for多层嵌套时,有时候需要直接跳出所有嵌套循环, 这时候就可以用到go的label breaks特征了。

先看一个范例代码:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. fmt.Println("1")
  7. Exit:
  8. for i := 0; i < 9; i++ {
  9. for j := 0; j < 9; j++ {
  10. if i+j > 15 {
  11. fmt.Print("exit")
  12. break Exit
  13. }
  14. }
  15. }
  16. fmt.Println("3")
  17. }

执行效果:

1

exit3

注意:label要写在for循环的开始而不是结束的地方。和goto是不一样的。虽然它是直接break退出到指定的位置。

break的标签和goto的标签的区别可以参考下面代码:

  1. JLoop:
  2. for i := 0; i < 10; i++ {
  3. fmt.Println("label i is ", i)
  4. for j := 0; j < 10; j++ {
  5. if j > 5 {
  6. //跳到外面去啦,但是不会再进来这个for循环了
  7. break JLoop
  8. }
  9. }
  10. }
  11. //跳转语句 goto语句可以跳转到本函数内的某个标签
  12. gotoCount := 0
  13. GotoLabel:
  14. gotoCount++
  15. if gotoCount < 10 {
  16. goto GotoLabel //如果小于10的话就跳转到GotoLabel
  17. }

break 标签除了可以跳出 for 循环,还可以跳出 select switch 循环, 参考下面代码:

  1. L:
  2. for ; count < 8192; count++ {
  3. select {
  4. case e := <-self.pIdCh:
  5. args[count] = e
  6. default:
  7. break L // 跳出 select 和 for 循环
  8. }
  9. }

continue 语句

跳过当前循环的剩余语句,然后继续进行下一轮循环。

Go 语言的 continue 语句 有点像 break 语句。但是 continue 不是跳出循环,而是跳过当前循环执行下一次循环语句。

for 循环中,执行 continue 语句会触发for增量语句的执行。

实例:

  1. package main
  2. import "fmt"
  3. func main() {
  4. /* 定义局部变量 */
  5. var a int = 10
  6. /* for 循环 */
  7. for a < 20 {
  8. if a == 15 {
  9. /* 跳过此次循环 */
  10. a = a + 1
  11. continue
  12. }
  13. fmt.Printf("a 的值为 : %d\n", a)
  14. a++
  15. }
  16. }

以上实例执行结果为:

  1. a 的值为 : 10
  2. a 的值为 : 11
  3. a 的值为 : 12
  4. a 的值为 : 13
  5. a 的值为 : 14
  6. a 的值为 : 16
  7. a 的值为 : 17
  8. a 的值为 : 18
  9. a 的值为 : 19

配合标签,break 和 continue 可在多级嵌套循环中跳出。

  1. func main() {
  2. L1:
  3. for x := 0; x < 3; x++ {
  4. L2:
  5. for y := 0; y < 5; y++ {
  6. if y > 2 { continue L2 }
  7. if x > 1 { break L1 }
  8. print(x, ":", y, " ")
  9. }
  10. println()
  11. }
  12. }

输出:

0:0 0:1 0:2

1:0 1:1 1:2

附:break 可用于 for、switch、select,而 continue 仅能用于 for 循环。

  1. x := 100
  2. switch {
  3. case x >= 0:
  4. if x == 0 { break }
  5. println(x)
  6. }

goto、continue、break语句:

  1. package main
  2. import "fmt"
  3. func main() {
  4. //goto直接调到LAbEL2
  5. for {
  6. for i := 0; i < 10; i++ {
  7. if i > 3 {
  8. goto LAbEL2
  9. }
  10. }
  11. }
  12. fmt.Println("PreLAbEL2")
  13. LAbEL2:
  14. fmt.Println("LastLAbEL2")
  15. //break跳出和LAbEL1同一级别的循环,继续执行其他的
  16. LAbEL1:
  17. for {
  18. for i := 0; i < 10; i++ {
  19. if i > 3 {
  20. break LAbEL1
  21. }
  22. }
  23. }
  24. fmt.Println("OK")
  25. //continue
  26. LABEL3:
  27. for i := 0; i < 3; i++ {
  28. for {
  29. continue LABEL3
  30. }
  31. }
  32. fmt.Println("ok")
  33. }

输出如下:

LastLAbEL2

OK

ok

本文标签:条件语句 循环语句 循环控制 if else switch select for range goto