11 流程控制

流程控制

流程控制是编程语言中用来控制程逻辑的走向和执行次序的语法/机制,大致分为三种

  • 1、顺序结构:从上向下,逐行执行
  • 2、选择结构:满足条件,某段代码才会执行1次,总共0-1次,例如分支语句:if,switch,select
  • 3、循环结构:满足条件,某段代码会被重复的执行多次,总共0-N次,例如循环语句:for

Go语言中最常用的流程控制有iffor,而switchgoto主要是为了简化代码、降低重复代码而生的结构,属于扩展类的流程控制。

一 if else(分支结构)

1、普通写法

完整语法如下

if 表达式1 {
    分支1
} else if 表达式2 {
    分支2
} else{
    分支3
}

// ps:可以单独一个if,也可以if只搭配else if,也可以if只搭配else,也可以if内嵌套if

Go语言规定

  • 1、与if匹配的左括号{必须与if和表达式放在同一行,{放在其他位置会触发编译错误。
  • 2、 理由同上,与else匹配的{也必须与else写在同一行,同时else也必须与上一个ifelse if右边的大括号在同一行。

举例

score := 60
if score >= 90 {
    fmt.Println("优")
} else if score >= 80 {
    fmt.Println("良")
} else {
    fmt.Println("差")
}

2、特殊写法

if条件判断还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断,举个如下

if score := 60;score >= 90 {
    fmt.Println("优")
} else if score >= 80 {
    fmt.Println("良")
} else {
    fmt.Println("差")
}

思考题: 普通写法与特殊写法的区别在哪里?

答案:特殊写法中声明的score只能在if判断内部使用

二 for(循环结构)

Go 语言中的所有循环类型均可以使用for关键字来完成。

2.1 for循环基本语法

for 初始语句;条件表达式;结束语句{
    循环体
}

for循环会一直循环执行循环体代码直到条件表达式返回false则终止循环,示例如下

for i := 0; i < 10; i++ {
    fmt.Println(i)
}

2.2 可以省略初始语句,但必须保留初始语句后的分号

i := 0
for ; i < 10; i++ {
    fmt.Println(i)
}

2.3 初始语句和结束语句也可以同时省略

i := 0
for i < 10 {
    fmt.Println(i)
    i++
}

上述写法类似于其他编程语言中的while,在while后添加一个条件表达式,满足条件表达式时持续循环,否则结束循环

2.4 死循环

for true {
    fmt.Println("ok")
}

// 可以直接省略true,如下所示
for {
    fmt.Println("ok")
}

for循环可以通过breakgotoreturnpanic语句强制退出循环。

2.5 for range循环

Go语言中可以使用for range遍历数组、切片、字符串、map 及通道(channel)。 通过for range遍历的返回值有以下规律:

  1. 数组、切片、字符串返回索引和值。

    // 1、循环数组
    names:=[4]string{"egon","张三","李四","王五"}
    for i,v:=range names{
    fmt.Println(i,v)
    }
    
    0 egon
    1 张三
    2 李四
    3 王五
    
    // 2、循环切片
    names:=[]string{"egon","张三","李四","王五"}
    for i,v:=range names{
       fmt.Println(i,v)
    }
    
    0 egon
    1 张三
    2 李四
    3 王五
    
    // 3、循环字符串
    for i,v:=range "hello你好"{
    fmt.Printf("%d    %q\n",i,v)
    }
    
    0    'h'
    1    'e'
    2    'l'
    3    'l'
    4    'o'
    5    '你'
    8    '好'
  2. map返回键和值

    ages:=map[string]int{
    "egon":18,
    "张三":20,
    "李四":30,
    }
    for i,v:=range ages{
    fmt.Println(i,v)
    }
    
    李四 30
    egon 18
    张三 20
  3. 通道(channel)只返回通道内的值。

三 switch case

3.1 switch case基本使用

使用switch语句可方便地对大量的值进行条件判断,从而减少大量if条件的次数,

day := 1
switch day {
case 1:
    fmt.Println("星期一")
case 2:
    fmt.Println("星期二")
case 3:
    fmt.Println("星期三")
case 4:
    fmt.Println("星期四")
case 5:
    fmt.Println("星期五")
case 6:
    fmt.Println("星期六")
case 0:
    fmt.Println("星期天")
default:
    fmt.Println("无效的输入!")
}

Go语言规定每个switch只能有一个default分支。

3.2 case分支同时判断多个值

一个case分支可以有多个值,多个case值中间使用英文逗号分隔。

day := 1
switch day {
case 1,2,3,4,5:
    fmt.Println("工作日")
case 6,0:
    fmt.Println("休息日")
default:
    fmt.Println("无效的输入!")
}

3.3 case分支使用表达式

分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量。例如:

level:=9
switch {
case level >= 20:
    fmt.Println("荣耀王者")
case level >= 10:
    fmt.Println("钻石玩家")
case level >= 0:
    fmt.Println("倔强青铜")
default:
    fmt.Println("无效的输入!")
}

3.4 fallthrough

fallthrough语法可以执行满足条件的case的下一个case,是为了兼容C语言中的case设计的。

level:=23
switch {
case level >= 20:
    fmt.Println("荣耀王者")
    fallthrough // 下一个case分支无论条件是否成立都会执行
case level >= 10:
    fmt.Println("钻石玩家")
case level >= 0:
    fmt.Println("倔强青铜")
default:
    fmt.Println("无效的输入!")
}

// 输出
荣耀王者
钻石玩家

四 goto(跳转到指定标签)

goto语句可以无条件地跳转到指定标签的位置

for i:=1;i<=2;i++{
    for j:=1;j<=3;j++{
        fmt.Printf("%v-%v\n",i,j)
        goto xxx // 直接跳到xxx的位置

    }
}
fmt.Println("后续其他代码1")
fmt.Println("后续其他代码2")
fmt.Println("后续其他代码3")

xxx:
    fmt.Println("飞过来。。。")

}

Go语言中使用goto语句能简化一些代码的实现过程,比如在快速跳出循环、避免重复退出上有一定的帮助。

例如:

//1、 break退出双层嵌套的for循环
breakTag := false

for i := 1; i <= 2; i++ {
    for j := 1; j <= 3; j++ {
        fmt.Printf("%v-%v\n", i, j)
        breakTag = true
        break
    }

    if breakTag {
        break
    }
}
fmt.Println("后续其他代码1")
fmt.Println("后续其他代码2")
fmt.Println("后续其他代码3")

//2、goto快速退出双层嵌套的for循环
for i := 1; i <= 2; i++ {
    for j := 1; j <= 3; j++ {
        fmt.Printf("%v-%v\n", i, j)
        goto xxx // 直接飞到指定的标签位置执行后续代码
    }

}

xxx:
    fmt.Println("后续其他代码1")
    fmt.Println("后续其他代码2")
    fmt.Println("后续其他代码3")    

五 break(跳出循环)

break语句可用于结束forswitchselect的代码块,如下

for i:=0;i<10;i++{
    if i==3 {
        break // 默认终止的就是本层循环
    }
    fmt.Println(i)

}

我们还可以在break语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的forswitchselect的代码块上,如下

var choice int

loop1:
    for {
        fmt.Println("===================>外层循环重新开始啦<===================")

    loop2:
        for {
            fmt.Print("内层循环,输0退出外层,输1只退内存: ")
            _, _ = fmt.Scan(&choice)
            if choice == 0 {
                break loop2  // 终止标签loop2对应的循环
            } else if choice == 1 {
                break loop1  // 终止标签loop1对应的循环
            }
        }
    }

fmt.Println("其他后续代码......")

六 continue(继续下次循环)

continue语句仅限在for循环内使用,用于结束当前/本次循环,直接进入下一次的循环

for i:=0;i<5;i++{
    if i==3 {
        continue
    }
    fmt.Println(i)

}

continue语句后添加标签时,表示由此直接进入标签对应的循环。例如:

var choice int
i:=0

loop1:
    for {
        fmt.Println("===================>外层循环重新开始啦<===================")

    loop2:
        for {
            fmt.Print("内层循环,输0重新进入loop2,输1重新进入loop1,输2继续: ")
            _, _ = fmt.Scan(&choice)
            if choice == 0 {
                continue loop2  // 终止标签loop2对应的循环
            } else if choice == 1 {
                continue loop1  // 终止标签loop1对应的循环
            }
            fmt.Println("姑娘站在门口冲你喊:来啊来啊来啊...",i)
            i++
        }

    }

七 综合练习

package main

import "fmt"

func main() {

    users := map[string]string{
        "egon": "123",
        "tom":  "456",
    }

    var inpUser string
    var inpPwd string
    var errNum int64 = 0

    for {
        if errNum == 3 {
            fmt.Println("超过最大尝试次数")
            break
        }
        fmt.Printf("请输入您的账号:")
        fmt.Scanln(&inpUser)

        fmt.Printf("请输入您的密码:")
        fmt.Scanln(&inpPwd)

        pwd := users[inpUser]
        if pwd == inpPwd {
            fmt.Println("登录成功")
        loop2:
            for {
                var choice string
                fmt.Printf(`
                1 起飞
                2 降落
                3 发射
                4、注销
                5、关机
                `)
                fmt.Scanln(&choice)

                switch {
                case choice == "1":
                    fmt.Println("起飞。。。")
                case choice == "2":
                    fmt.Println("降落。。。")
                case choice == "3":
                    fmt.Println("发射。。。")
                case choice == "4":
                    break loop2 // 直接干掉loop2的for
                    //break  // 这个break负责干掉switch
                case choice == "5":
                    goto xxx
                default:
                    fmt.Println("输入命令不存在")
                }
                //break  // 这个break负责干掉本层for
            }
        } else {
            fmt.Println("账号或密码错误")
            errNum++
        }

    }

xxx:
    fmt.Println("关机走人")

}
上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术