流程控制
流程控制是编程语言中用来控制程逻辑的走向和执行次序的语法/机制,大致分为三种
- 1、顺序结构:从上向下,逐行执行
- 2、选择结构:满足条件,某段代码才会执行1次,总共0-1次,例如分支语句:if,switch,select
- 3、循环结构:满足条件,某段代码会被重复的执行多次,总共0-N次,例如循环语句:for
Go语言中最常用的流程控制有if
和for
,而switch
和goto
主要是为了简化代码、降低重复代码而生的结构,属于扩展类的流程控制。
一 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
也必须与上一个if
或else 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循环可以通过break
、goto
、return
、panic
语句强制退出循环。
2.5 for range循环
Go语言中可以使用for range
遍历数组、切片、字符串、map 及通道(channel)。 通过for range
遍历的返回值有以下规律:
-
数组、切片、字符串返回索引和值。
// 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 '好'
-
map返回键和值
ages:=map[string]int{ "egon":18, "张三":20, "李四":30, } for i,v:=range ages{ fmt.Println(i,v) } 李四 30 egon 18 张三 20
-
通道(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
语句可用于结束for
、switch
和select
的代码块,如下
for i:=0;i<10;i++{
if i==3 {
break // 默认终止的就是本层循环
}
fmt.Println(i)
}
我们还可以在break
语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的for
、switch
和 select
的代码块上,如下
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("关机走人")
}