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 版权所有 沪ICP备2022009235号 沪公网安备31011802005110号 青浦区尚茂路798弄 联系方式-13697081366