在程序中,程序运行的流程控制决定程序是如何执行的,主要有三大流程控制语句:顺序控制,分支控制,循环控制。
一、顺序控制
程序从上到下逐行地执行,中间没有任何判断和跳转。
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 ", str[i])
}
fmt.Println()
//字符串遍历方式2 for - range
str = "abcdef"
for index, val := range str {
fmt.Printf("index = %d val = %c
", 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 ", str2[i])
}
fmt.Println()
//for - range 方式遍历有中文的字符串
str = "abdedf上海"
for index, val := range str {
fmt.Printf("index = %d val = %c
", 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
", 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个学生的成绩
", i, j)
fmt.Scanln(&score)
sum += score
}
fmt.Printf("第%d个班级的平均分是%v
", i, sum/float64(stuNum))
totalSum += sum
}
fmt.Printf("各个班级的总成绩%v,所有班级平均分是%v
", 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 ", 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个
", 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")
}