当前位置:   article > 正文

go语言流程控制

go语言流程控制

1. if else

1.1 if条件判断基本写法

  1. if 布尔表达式1 {
  2. 分支1
  3. } else if 布尔表达式2 {
  4. 分支2
  5. } else{
  6. 分支3
  7. }

布尔表达式1的结果为true时,执行分支1,否则判断布尔表达式2,如果满足则执行分支2,都不满足时,则执行分支3。 if判断中的else ifelse都是可选的,可以根据实际需要进行选择。

1.2 if条件判断特殊写法

在 if 表达式之前添加一个执行语句

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

2.switch case

switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上直下逐一测试,直到匹配为止。 Golang switch 分支表达式可以是任意类型,不限于常量。可省略 break,默认自动终止,但是可以使用fallthrough强制执行后面的case代码。

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

2.1 基本写法

  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. }

以上代码执行结果为:

  1. 优秀!
  2. 你的等级是 A

 2.2 Type Switch

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

  1. switch x.(type){
  2. case type:
  3. statement(s)
  4. case type:
  5. statement(s)
  6. /* 你可以定义任意个数的case */
  7. default: /* 可选 */
  8. statement(s)
  9. }

例如:

  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. }

以上代码执行结果为:

    x 的类型 :<nil>

 3.select

3.1 select语句

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

  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. // = <-c1 表示等待并接收c1通道的数据
  8. case i1 = <-c1:
  9. fmt.Printf("received ", i1, " from c1\n")
  10. case c2 <- i2:
  11. fmt.Printf("sent ", i2, " to c2\n")
  12. case i3, ok := (<-c3): // same as: i3, ok := <-c3
  13. if ok {
  14. fmt.Printf("received ", i3, " from c3\n")
  15. } else {
  16. fmt.Printf("c3 is closed\n")
  17. }
  18. default:
  19. fmt.Printf("no communication\n")
  20. }
  21. }

 以上代码执行结果为:

    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会按顺序从头到尾评估每一个发送和接收的语句。

如果其中的任意一个语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用。 如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有两种可能的情况:

①如果给出了default语句,那么就会执行default的流程,同时程序的执行会从select语句后的语句中恢复。
②如果没有default语句,那么select语句将被阻塞,直到至少有一个case可以进行下去。 

3.2 典型用法

1.超时判断

  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. }

2.退出

  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)

3.判断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循环是一个循环控制结构,可以执行指定次数的循环。

普通for循环:

for init; condition; post { }
  • init: 一般为赋值表达式,给控制变量赋初值;
  • condition: 关系表达式或逻辑表达式,循环控制条件;
  • post: 一般为赋值表达式,给控制变量增量或减量。 

替代while的for循环:

for condition { }

替代 while (true)的for循环:

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. }
  13. for i,x:= range numbers { //range使用方法
  14. fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
  15. }

上面for循环优化:

  1. func main() {
  2. s := "abcd"
  3. for i, n := 0, len(s); i < n; i++ { // 避免多次调用 len 函数。
  4. println(i, s[i])
  5. }
  6. }

5 循环语句range

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

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

  1. for key, value := range oldMap {
  2. newMap[key] = value
  3. }

通过for range遍历的返回值有以下规律:

  1. 数组、切片、字符串返回索引和值。
  2. map返回键和值。
  3. 通道(channel)只返回通道内的值。
  4. 可忽略不想要的返回值,或 "_" 这个特殊变量。
1st value2nd value
stringindexs[index]unicode, rune
array/sliceindexs[index]
mapkeym[key]
channelelement

 使用:

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

6.goto(跳转到指定标签)

goto语句通过标签进行代码间的无条件跳转。goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。

例如双层嵌套的for循环要退出时:

  1. func gotoDemo2() {
  2. for i := 0; i < 10; i++ {
  3. for j := 0; j < 10; j++ {
  4. if j == 2 {
  5. // 设置退出标签
  6. goto breakTag
  7. }
  8. fmt.Printf("%v-%v\n", i, j)
  9. }
  10. }
  11. return
  12. // 标签
  13. breakTag:
  14. fmt.Println("结束for循环")
  15. }

7.break(跳出循环)

break语句可以结束forswitchselect的代码块。单个跳出循环直接break,多层跳出指定一下就行了。

  1. func breakDemo1() {
  2. BREAKDEMO1:
  3. for i := 0; i < 10; i++ {
  4. for j := 0; j < 10; j++ {
  5. if j == 2 {
  6. break BREAKDEMO1
  7. }
  8. fmt.Printf("%v-%v\n", i, j)
  9. }
  10. }
  11. fmt.Println("...")
  12. }

8.continue(继续下次循环)

continue语句可以结束当前循环,开始下一次的循环迭代过程,仅限在for循环内使用。

  1. func continueDemo() {
  2. forloop1:
  3. for i := 0; i < 5; i++ {
  4. // forloop2:
  5. for j := 0; j < 5; j++ {
  6. if i == 2 && j == 2 {
  7. continue forloop1
  8. }
  9. fmt.Printf("%v-%v\n", i, j)
  10. }
  11. }
  12. }

 

参考文件:

条件语句if :https://www.fansimao.com/991496.html

switch case: https://www.fansimao.com/991511.html

go条件语句select : https://www.fansimao.com/991523.html

go 循环语句for : https://www.fansimao.com/991534.html

go 循环语句range: https://www.fansimao.com/991545.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/42776
推荐阅读
相关标签
  

闽ICP备14008679号