程序流程控制
在程序中,程序运行的流程控制决定程序是如何执行的,主要有三大流程控制语句:顺序控制,分支控制,循环控制。
一、顺序控制
程序从上到下逐行地执行,中间没有任何判断和跳转。
Golang 中定义变量时采用合法的前向引用。
二、分支控制
分支控制就是让程序有选择执行。有三种形式:单分支、双分支、多分支。
1、单分支控制
if 条件表达式{
执行代码块
}
当条件表达式为true时,就会执行{}的代码。{}是必须要有的,就算只写一行代码。
package main import "fmt" func main() { //编写一个程序,可以输入人的年龄,如果该同志的年龄大于 18 岁,则输出 "你年龄大 于 18,要对自己的行为负责!" var age int fmt.Println("请输入年龄") fmt.Scanln(&age) if age > 18 { fmt.Println("你年龄大 于 18,要对自己的行为负责!") } }
单分支的流程图:
golang支持在if中直接定义一个变量
package main import "fmt" func main() { //golang支持在if中直接定义一个变量 if age :=20;age>18{ fmt.Println("你的年龄大于18,要对自己的行为负责!") } }
2、双分支控制
if 条件表达式{
执行代码块1
}else{
执行代码块2
}
当条件表达式成立时,执行代码块1,否则执行代码块2。{}也是必须有的。
package main import "fmt" func main() { //编写一个程序,输入年龄,如果年龄大于 18 岁,则输出 “你年龄大于18,要对自己的行为负责!”。否则 输出”你的年龄不大这次放过你了” var age int fmt.Println("请输入年龄:") fmt.Scanln(&age) if age > 18 { fmt.Println("你年龄大于18,要对自己的行为负责!") } else { fmt.Println("你的年龄不大这次放过你了") } }
判断一个年份是否是闰年,闰年的条件是符合下面二者之一:(1)年份能被4整除,但不能被100 整除;(2)能被400整除
package main import "fmt" func main() { //判断一个年份是否是闰年,闰年的条件是符合下面二者之一:(1)年份能被4整除,但不能被100 整除;(2)能被400整除 var year int fmt.Println("请输入年份") fmt.Scanln(&year) if (year%4 == 0 && year%100 != 0) || (year%400 == 0) { fmt.Println(year, "是闰年") } }
3、多分支控制
if 条件表达式1{
执行代码块1
}else if 条件表达式2{
执行代码块2
}else{
执行代码块n
}
多分支的判断流程如下:
(1)先判断条件表达式1是否成立,如果为真,就执行代码块1
(2)如果条件表达式1为假,就去判断条件表达式2是否成立, 如果条件表达式2为真, 就执行代码块2
(3)依次类推.
(4)如果所有的条件表达式不成立,则执行else的语句块。
else语句不是必须的。
多分支只能有一个执行入口。
嵌套分支:
在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分 支外面的分支结构称为外层分支。
基本语法:
if 条件表达式{
if 条件表达式{
执行语句1
}else{
执行语句2
}
}else{
执行语句
}
注意:嵌套分支不宜过多,建议控制在3层内。
4、练习题
(1)、参加百米运动会,如果用时8秒以内进入决赛,否则提示淘汰。并且根据性别提示进入男子组或女子组。
package main import "fmt" func main() { var second float64 fmt.Println("请输入秒数") fmt.Scanln(&second) if second <= 8 { var gender string fmt.Println("请输入性别") fmt.Scanln(&gender) if gender == "男" { fmt.Println("进入决赛的男子组") } else { fmt.Println("进入决赛的女子组") } } else { fmt.Println("out...") } }
(2)、出票系统:根据淡旺季的月份和年龄,打印票价。
package main import "fmt" func main() { var month byte var age byte var price float64 = 60.0 fmt.Println("请输入游玩月份") fmt.Scanln(&month) fmt.Println("请输入游客年龄") fmt.Scanln(&age) if month >= 4 && month <= 10 { if age > 60 { fmt.Printf("%v月 票价 %v 年龄 %v ", month, price/3, age) } else if age >= 18 { fmt.Printf("%v月 票价 %v 年龄 %v ", month, price, age) } else { fmt.Printf("%v月 票价 %v 年龄 %v ", month, price/2, age) } } else { if age >= 18 && age < 60 { fmt.Println("淡季成人票价40") } else { fmt.Println("淡季儿童和成人票价20") } } }
5、switch分支控制
switch语句用于基于不同条件执行不同动作,每一个case分支都是唯一的,从上到下逐一测 试,直到匹配为止。
匹配项后面也不需要再加break
switch 表达式{
case 表达式1,表达式2,... :
语句块1
case 表达式3,表达式4,... :
语句块2
......
default :
语句块
}
switch执行流程:
(1)、先执行表达式得到值,然后和case的表达式进行比较,如果匹配就执行对应的case语句块,然后退出switch控制。
(2)、如果switch的表达式的值没有和任何的case的表达式匹配成功,则执行default的语句块。执行后退出switch的控制。
golang的case后的表达式可以有多个,使用逗号间隔。
golang中的case语句块不需要写break , 因为默认会有,即在默认情况下,当程序执行完case语句块后,就直接退出该switch控制结构。
package main import "fmt" func main() { var char byte fmt.Println("请输入一个字符") fmt.Scanf("%c", &char) switch char { case 'a': fmt.Println("A") case 'b': fmt.Println("B") case 'c': fmt.Println("C") case 'd': fmt.Println("D") case 'e': fmt.Println("E") default: fmt.Println("other") } }
switch使用的注意事项:
(1)、case/switch 后是一个表达式( 即:常量值、变量、一个有返回值的函数等都可以)
(2)、case后的各个表达式的值的数据类型,必须和 switch 的表达式数据类型一致
(3)、case后面可以带多个表达式,使用逗号间隔。比如case 表达式 1, 表达式 2 ...
(4)、case后面的表达式如果是常量值(字面量),则要求不能重复
(5)、case后面不需要带break , 程序匹配到一个case后就会执行对应的代码块,然后退出switch,如 果一个都匹配不到,则执行default
(6)、default语句不是必须的
(7)、switch后也可以不带表达式,类似 if else分支来使用。
package main import "fmt" func main() { //switch后也可以不带表达式,类似 if else分支来使用。 var age int = 10 switch { case age == 10: fmt.Println("age is 10") case age == 20: fmt.Println("age is 20") default: fmt.Println("没有匹配") } //case中也可以对范围进行判断 var score int = 90 switch { case score > 90: fmt.Println("成绩优秀") case score >= 70 && score <= 90: fmt.Println("成绩良好") case score >= 60 && score < 70: fmt.Println("成绩及格") default: fmt.Println("不及格") } }
(8)、switch后也可以直接声明/定义一个变量,分号结束【不推荐】。
package main import "fmt" func main() { //switch后也可以直接声明/定义一个变量,分号结束【不推荐】 switch grade := 90; { case grade > 90: fmt.Println("成绩优秀") case grade >= 70 && grade <= 90: fmt.Println("成绩良好") case grade >= 60 && grade < 70: fmt.Println("成绩及格") default: fmt.Println("不及格") } }
(9)、switch 穿透-fallthrough ,如果在case语句块后增加fallthrough ,则会继续执行下一个case,也叫switch穿透。默认只能穿透一层
package main import "fmt" func main() { //switch 穿透 fallthrough var num int = 10 switch num { case 10: fmt.Println("ok") fallthrough //默认只能穿透一层 case 20: fmt.Println("ok2") fallthrough case 30: fmt.Println("ok3") default: fmt.Println("没有匹配到") } }
对学生成绩大于60分的,输出“合格”。低于60分的,输出“不合格”。(注:输入的成绩不能大于100)
package main import "fmt" func main() { //对学生成绩大于60分的,输出“合格”。低于60分的,输出“不合格”。(注:输入的成绩不能大于100) var score float64 fmt.Println("请输入成绩") fmt.Scanln(&score) switch int(score / 60) { case 1: fmt.Println("及格") case 0: fmt.Println("不及格") default: fmt.Println("输入有误") } }
根据用户指定月份,打印该月份所属的季节。3,4,5 春季 6,7,8 夏季 9,10,11 秋季 12, 1, 2 冬季
package main import "fmt" func main() { //根据用户指定月份,打印该月份所属的季节。3,4,5 春季 6,7,8 夏季 9,10,11 秋季 12, 1, 2 冬季 var month byte fmt.Println("请输入月份") fmt.Scanln(&month) switch month { case 3, 4, 5: fmt.Println("spring") case 6, 7, 8: fmt.Println("summer") case 9, 10, 11: fmt.Println("autumn") case 12, 1, 2: fmt.Println("winter") default: fmt.Println("输入有误") } }
switch和if的比较:
(1)、如果判断的具体数值不多,而且符合整数、浮点数、字符、字符串这几种类型。建议使用swtich语句,简洁高效。
(2)、其他情况:对区间判断和结果为 bool 类型的判断,使用if,if的使用范围更广。
三、循环控制
1、for循环控制
for 循环变量初始化;循环条件;循环变量迭代{
循环操作语句
}
for循环的四个要素:
(1)、循环变量初始化
(2)、循环条件
(3)、循环操作语句,也叫循环体
(4)、循环变量迭代
循环条件是返回一个布尔值的表达式。
for循环流程图:
package main import "fmt" func main() { for i := 1; i <= 10; i++ { fmt.Println("hello world") } }
for循环的第二种使用方式:
for 循环判断条件{
循环体
}
package main import "fmt" func main() { j := 1 for j <= 10 { fmt.Println("golang go", j) j++ } }
for循环的第三种使用方式:
for {
循环体
}
等价于 for ; ;{}是一个无限循环,通常需要配合break语句使用
package main import "fmt" func main() { k := 1 for { if k <= 10 { fmt.Println("ok~~", k) } else { break } k++ } }
for - range遍历字符串和数组
package main import "fmt" func main() { //字符串遍历方式1 var str string = "hello,world" for i := 0; i < len(str); i++ { fmt.Printf("%c \t", str[i]) } fmt.Println() //字符串遍历方式2 for - range str = "abcdef" for index, val := range str { fmt.Printf("index = %d val = %c\n", index, val) } }
如果字符串含有中文,那么传统的遍历字符串方式,就是错误,会出现乱码。原因是传统的对字符串的遍历是按照字节来遍历,而一个汉字在utf8编码是对应3个字节。需要要将 str 转成 []rune 切片才能解决。
package main import "fmt" func main() { //[]rune切片方式遍历有中文的字符串 var str string = "hello,world北京" str2 := []rune(str) for i := 0; i < len(str2); i++ { fmt.Printf("%c \t", str2[i]) } fmt.Println() //for - range 方式遍历有中文的字符串 str = "abdedf上海" for index, val := range str { fmt.Printf("index = %d val = %c\n", index, val) } }
打印1~100之间所有是9的倍数的整数的个数及总和
package main import "fmt" func main() { //打印1~100之间所有是9的倍数的整数的个数及总和 var max uint64 = 100 var count uint64 = 0 var sum uint64 = 0 var i uint64 = 1 for ; i <= max; i++ { if i%9 == 0 { count++ sum += i } } fmt.Printf("count = %v sum = %v\n", count, sum) }
2、while循环和do while循环
golang语言中没有while和do while循环。
如果需要使用while循环和do while循环类似的循环,可以通过for循环来实现其使用效果。
(1)、while循环的实现:
循环变量初始化
for{
if 循环条件表达式{
break //跳出for循环
}
循环体
循环变量迭代
}
package main import "fmt" func main() { var i int = 1 for { if i > 10 { break } fmt.Println("hello,world", i) i++ } fmt.Println("i = ", i) }
(2)、do while循环的实现:
循环变量初始化
for{
循环体
循环变量迭代
if 循环条件表达式{
break //跳出for循环
}
}
package main import "fmt" func main() { var j int = 1 for { fmt.Println("ok ", j) j++ if j > 10 { break } } fmt.Println("j = ", j) }
3、多重循环控制
将一个循环放在另一个循环体内,就形成了嵌套循环。在外边的for称为外层循环在里面的for循环称为内层循环。【建议一般使用两层,最多不要超过3层】
实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环。
外层循环次数为m次,内层为n次,则内层循环体实际上需要执行m*n次
统计3个班成绩情况,每个班有5名同学,求出各个班的平均分和所有班级的平均分[学生的成 绩从键盘输入]
package main import "fmt" func main() { //统计3个班成绩情况,每个班有5名同学,求出各个班的平均分和所有班级的平均分[学生的成 绩从键盘输入] var classNum int = 2 var stuNum int = 5 var totalSum float64 = 0.0 for i := 1; i <= classNum; i++ { sum := 0.0 for j := 1; j <= stuNum; j++ { var score float64 fmt.Printf("请输入第%d班 第%d个学生的成绩\n", i, j) fmt.Scanln(&score) sum += score } fmt.Printf("第%d个班级的平均分是%v\n", i, sum/float64(stuNum)) totalSum += sum } fmt.Printf("各个班级的总成绩%v,所有班级平均分是%v\n", totalSum, totalSum/float64(stuNum*classNum)) }
4、练习题
(1)、打印一个矩形
package main import "fmt" func main() { for i := 1; i <= 3; i++ { for j := 1; j <= 3; j++ { fmt.Print("* ") } fmt.Println() } }
(2)、打印半个金字塔
package main import "fmt" func main() { for i := 1; i <= 3; i++ { for j := 1; j <= i; j++ { fmt.Print("* ") } fmt.Println() } }
(3)、打印整个金字塔
package main import "fmt" func main() { tower(5) fmt.Println() tower2(5) } func tower(level int) { for i := 1; i <= level; i++ { for j := 1; j <= level-i; j++ { fmt.Print(" ") } for n := 1; n < i; n++ { fmt.Print("* ") } for k := 1; k <= i; k++ { fmt.Print("* ") } fmt.Println() } } func tower2(level int) { for i := 1; i <= level; i++ { for j := 1; j <= level-i; j++ { fmt.Print(" ") } for k := 1; k <= 2*i-1; k++ { fmt.Print("* ") } fmt.Println() } }
(4)、打印空心金字塔
package main import "fmt" func main() { tower(9) } func tower(level int) { for i := 1; i <= level; i++ { for j := 1; j <= level-i; j++ { fmt.Print(" ") } for k := 1; k <= 2*i-1; k++ { if k == 1 || k == 2*i-1 || i == level { fmt.Print("* ") } else { fmt.Print(" ") } } fmt.Println() } }
(5)、打印九九乘法表
package main import "fmt" func main() { //打印九九乘法表 var num int = 9 for i := 1; i <= num; i++ { for j := 1; j <= i; j++ { fmt.Printf("%v * %v = %v \t", j, i, j*i) } fmt.Println() } }
四、跳转控制语句
1、break
随机生成 1-100 的一个数,直到生成了 99 这个数,看看你一共用了几次?
package main import ( "fmt" "math/rand" "time" ) func main() { var count int = 0 //time.Now().Unix()返回一个从1970:01:01的0时0分0秒到现在的秒数 for { rand.Seed(time.Now().UnixNano()) //在go中生成随机数需要一个种子,否则返回的值总是固定的。 n := rand.Intn(100) + 1 //[0 100) fmt.Println("n = ", n) count++ if (n == 9) { break } } fmt.Println("生成99一共使用了", count, "次") }
break语句用于终止某个语句块的执行,用于中断当前for循环或跳出switch语句。
break的注意事项和使用细节:
break语句出现在多层嵌套的语句块中时,可以通过标签指明要终止的是哪一层语句块。
package main import "fmt" func main() { lable2: for i := 0; i < 4; i++ { //lable1: for j := 0; j < 10; j++ { if j == 2 { break lable2 } fmt.Println("j = ", j) } } }
练习题:100以内的数求和,求出当和第一次大于20的当前数
package main import "fmt" func main() { //100以内的数求和,求出当和第一次大于20的当前数 sum := 0 for i := 1; i <= 100; i++ { sum += i if sum > 20 { fmt.Println("当sum>20时,当前数是", i) break } } }
2、continue
continue语句用于结束本次循环,继续执行下一次循环。
continue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这 个和前面的break标签的使用的规则一样。
package main import "fmt" func main() { for i := 0; i < 4; i++ { for j := 0; j < 10; j++ { if j == 2 { continue } fmt.Println("j = ", j) } fmt.Println() } }
打印1——100之内的奇数[要求使用for循环+continue]
package main import "fmt" func main() { //打印1——100之内的奇数[要求使用for循环+continue] for i := 1; i <= 100; i++ { if i%2 == 0 { continue } fmt.Println("奇数是", i) } }
从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为0时结束程序
package main import "fmt" func main() { //从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为0时结束程序 var positiveCount int var negativeCount int var num int for { fmt.Println("请输入一个整数") fmt.Scanln(&num) if num == 0 { break } if num > 0 { positiveCount++ continue } negativeCount++ } fmt.Printf("正数有%v个,负数有%v个\n", positiveCount, negativeCount) }
3、goto
(1)、语言的goto语句可以无条件地转移到程序中指定的行。
(2)、goto语句通常与条件语句配合使用。可用来实现条件转移,跳出循环体等功能。
(3)、在go程序设计中一般不主张使用goto语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。
package main import "fmt" func main() { var n int = 30 fmt.Println("ok") if n > 20 { goto lable1 } fmt.Println("ok1") fmt.Println("ok2") fmt.Println("ok3") lable1: fmt.Println("ok4") fmt.Println("ok5") }
4、return
return使用在方法或者函数中,表示跳出所在的方法或函数。
如果return是在普通的函数,则表示跳出该函数,即不再执行函数中return后面代码,也可以理解成终止函数。
如果return是在main函数,表示终止main函数,也就是说终止程序。
package main import "fmt" func main() { for i := 1; i <= 10; i++ { if i == 3 { return } fmt.Println("i = ", i) } fmt.Println("hello world") }