流程控制语句分类:
流程控制语句可以控制代码的执行顺序和条件
顺序结构:
普通的代码,由上而下依次执行分支结构(if, switch)
循环结构(for)
if语句:
条件表达式值必须是bool类型,不可省略括号,且左大括号不能另起一行
格式1:
if (关系表达式) {
语句体;
}
执行流程:
- 首先计算关系表达式的值
- 如果关系表达式的值为true就执行语句体
- 如果关系表达式的值为false就不执行语句体
- 继续执行后面的语句内容
if语句格式2:
if (关系表达式) {
语句体1;
} else {
语句体2;
}
执行流程:
- 首先计算关系表达式的值
- 如果关系表达式的值为true就执行语句体1
- 如果关系表达式的值为false就执行语句体2
- 继续执行后面的语句内容
if语句格式3:
if (关系表达式1) {
语句体1;
} else if (关系表达式2) {
语句体2;
}
…
else {
语句体n+1;
}
执行流程:
1. 首先计算关系表达式1的值
2. 如果值为true就执行语句体1;如果值为false就计算关系表达式2的值
3. 如果值为true就执行语句体2;如果值为false就计算关系表达式3的值
4. …
5. 如果没有任何关系表达式为true,就执行语句体n+1。
定义一个在0~100之间的变量a, 判断分数在什么范围,90 ~ 100优秀,80 ~ 89良好,70 ~ 79中等,60 ~ 69及格,0 ~ 59请努力加油!
func main() {
// 定义一个在0~100之间的变量a, 判断分数在什么范围,90 ~ 100优秀,80 ~ 89良好,70 ~ 79中等,60 ~ 69及格,0 ~ 59请努力加油!
var a float64
fmt.Println("请输入成绩:")
fmt.Scan(&a)
if a >= 90 && a <= 100 {
fmt.Println("优秀")
} else if a >= 80 && a <= 89 {
fmt.Println("良好")
} else if a >= 70 && a <= 79 {
fmt.Println("中等")
} else if a >= 60 && a <= 69 {
fmt.Println("及格")
} else if a >= 0 && a <= 59 {
fmt.Println("有脸吃饭?")
} else {
fmt.Println("成绩需在0~100之间")
}
}
死代码:指永远不会被执行的代码,数据被定义成常量时就容易产生死代码
func main() {
x := 8
if x > 5 { //优先判断,条件表达式结果为true。
println("a")
} else if x > 7 { // 永远不会执行
println("b")
}
}
在if中可以定义局部变量赋值后再做条件判断,可以调用函数时传参再判断
func main() {
if age := 18; age <= 18 {
fmt.Println()
}
age // 只能在if中使用
}
switch语句:
- switch和case后面是一个表达式,也可以是常量、变量、有返回值的函数,switch后面也可以不带表达式,无表达式时为true
- case常量值不能重复,case后的表达式可以有多个,使用逗号间隔
- Go语言中的switch默认给每个case自带break,因此匹配成功后不会向下执行其他的 case 分支,而是跳出整个switch
- 如需要穿透后续的case须使用fallthrough强制执行下一个的case代码,switch只能穿透一个case,fallthrough必须放在case分支的最后一行,否则编译报错。
- 如果所有的case都和表达式的值不匹配,就会执行default语句体部分,default不是必须要写的
格式:
switch (表达式) {
case 1:
语句体1
case 2:
语句体2
...
default:
语句体
}
执行流程:
- 首先计算出表达式的值
- 其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
- 最后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分,然后程序结束掉。 所以建议将default放在末尾
定义一个在0~100之间的变量a,判断分数在什么范围,90 ~ 100优秀,80 ~ 89良好,70 ~ 79中等,60 ~ 69及格,0 ~ 59请努力加油!
func main() {
var score float64
fmt.Println("请输入成绩:")
_, err := fmt.Scan(&score)
if err != nil {
return
}
switch {
case score >= 90 && score <= 100:
fmt.Println("优秀")
case score >= 80 && score <= 89:
fmt.Println("良好")
case score >= 70 && score <= 79:
fmt.Println("中等")
case score >= 60 && score <= 69:
fmt.Println("及格")
case score >= 0 && score <= 59:
fmt.Println("有脸吃饭?")
default:
fmt.Println("成绩必须在0~100之间")
}
}
case表达式值的数据类型必须和switch的数据类型一致
func main() {
var num1 int = 1
var num2 int64 = 1
var num3 float64 = 1
switch num1 {
case num2: // 报错:'num1' (类型 'int64' 和 'int' 不匹配) 的 switch 中的 case 'num2' 无效
fmt.Println(num2)
case num3: // 报错:'num1' (类型 'int64' 和 'int' 不匹配) 的 switch 中的 case 'num2' 无效
fmt.Println(num2)
default:
fmt.Println("error")
}
}
case的后面可以有多个表达式,使用逗号间隔即可,但case的表达式后面如果跟的是常量值,则要求不能重复
func main() {
var num1 int = 1
var num2 int = 1
switch num1 {
case num2, 2, 3:
fmt.Println("没问题")
case 3: // 报错:case 3的值重复,常量值不能重复
fmt.Println("有问题")
case num1 + num2: // 这里的结果也是2,但是不是常量值,所以不会报错
fmt.Println("没问题")
}
}
fallthrough必须放在case块结尾
func main() {
var num int = 10
switch num {
case 10:
fmt.Println("case 10 匹配成功")
fallthrough // 默认只能穿透一层
case 20:
fmt.Println("只能穿透到这里")
case 30:
fmt.Println("case 30 匹配成功")
default:
fmt.Println("default")
}
}
输出:
case 10 匹配成功
只能穿透到这里
fallthrough如果放在default的前面,则会穿透default
func main() {
var num int = 30
switch num {
case 10:
fmt.Println("case 10 匹配成功")
case 20:
fmt.Println("case 20 匹配成功")
case 30:
fmt.Println("case 30 匹配成功")
fallthrough // 默认只能穿透一层
default:
fmt.Println("default")
}
}
输出:
case 30 匹配成功
default
如果fallthrough前面手动执行break就会中断fallthrough执行
func main() {
var num int = 50
switch num {
default:
fmt.Println("default在fallthrough前,则不会执行default")
case 10:
fmt.Println("case 10 匹配成功")
case 20:
fmt.Println("case 20 匹配成功")
break // 如果执行fallthrough前手动break就会中断fallthrough执行
fallthrough // 默认只能穿透一层
case 30:
fmt.Println("走到这里说明被穿透了")
}
}
switch还被用来替换if语句,被省略的switch条件表达式默认值为true,继而与case比较表达式结果匹配
func main() {
switch x := 5; { // 相当于定义了变量x=5,"switch x := 5; true { ... } ,但是一定要加分号,否则报错
case x > 5:
fmt.Println("x > 5")
case x > 0 && x <= 5: // 多条件是 OR 关系,不能写成“case x > 0, x <= 5”。
fmt.Println("x > 0 && x <= 5")
default:
fmt.Println("default")
}
}
for循环
循环语句可以在满足循环条件的情况下,反复执行某一段代码
,这段被重复执行的代码被称为循环体语句,当反复执行这个循环体时,需要在合适的时候把循环判断条件修改为false,从而结束循环,否则循环将一直执行下去,形成死循环。
range和fori循环中的局部变量都会被重复使用
for (初始化语句;条件判断语句;条件控制语句) {
循环体语句;
}
// 三种for定义格式:
func main() {
// 格式1
for i := 0; i < 3; i++ {}//初始化表达式支持函数调用或定义局部变量。
x := 3
for x < 10 { // 循环外定义初始化
x++
}
for { // 死循环,相当于"while true {}” 或 “for true {}”。
循环体语句
}
for ; ; {} // 死循环,只不过格式不同
}
格式解释:
初始化语句
: 用于表示循环开启时的起始状态,就是循环开始的时候什么样条件判断语句
:用于表示循环反复执行的条件,就是判断循环是否能一直执行下去循环体语句
: 用于表示循环反复执行的内容,就是循环反复执行的事情条件控制语句
:用于表示循环执行中每次变化的内容,就是控制循环是否能执行下去
执行流程:
- 执行初始化语句
- 执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行- 执行循环体语句
- 执行条件控制语句
- 回到2继续
求1-100之间的偶数和,并把求和结果在控制台输出
func main() {
var sum int
for i := 0; i <= 100; i++ {
if i%2 == 0 {
sum += i
}
}
fmt.Println(sum)
}
// 每次直接加2,不需要if判断
func main() {
var sum int
for i := 2; i <= 100; i += 2 {
sum += i
}
fmt.Println(sum)
}
可以遍历字符串和数组
func main() {
var name string = "itzhuzhu"
for i := 0; i < len(name); i++ {
fmt.Printf("%c\n", name[i])
}
}
如果遍历的字符串内含有中文会报错,因为遍历是按照字节来的,一个中文占用3个字节,需要转成切片再遍历,或者使用range遍历,range是按照字符遍历的
func main() {
var name string = "itzhuzhu我乱码了吗"
str := []rune(name)
for i := 0; i < len(str); i++ {
fmt.Printf("%c\n", str[i])
}
}
range方式遍历
func main() {
var name string = "haha我乱码了吗"
for i, v := range name {
fmt.Printf("索引:%d,数据:%c", i, v)
}
}
range
- range本质是一个函数,在使用的时候可以加括号使用
- 修改range得到的value不影响原切片/数组的数据,value就是个副本,和原数据无关,但是在range循环里打印的话还是副本的内容
- range和fori循环中的局部变量都会被重复使用
range 关键字用于
- for循环中迭代数组、切片、channel、map的元素
- 在数组和切片中它返回元素的索引值
- 在集合中返回 key-value 对的 key 值
格式:
// for 索引,值 := range 循环数据
for index,value := range arr {}
通过参数列表传递多个参数,使用range获取数据
func main() {
//Demo01(1, 2, 3, 4, 5)
//Demo02(1, 2, 3, 4, 5)
Demo03(1, 2, 3, 4, 5)
}
// i代表索引 v代表数据
func Demo01(num ...int) {
for i, v := range num {
fmt.Print("i = ", i, " ")
fmt.Println("v = ", v)
}
}
// 如果只写一个变量,取出的是索引
func Demo02(num ...int) {
for v := range num {
//fmt.Print("a = ", a, " ")
fmt.Println("v = ", v)
}
}
// 可以把a使用_代替,表示是一个匿名变量,匿名变量不会保存具体的数据,就可以用v取出数据
func Demo03(num ...int) {
for _, v := range num {
//fmt.Print("a = ", a, " ")
fmt.Println("v = ", v)
}
}
演示:
type Student struct {
name string
age int
}
func main() {
s := Student{"韩信", 10}
s2 := Student{"娜可露露", 20}
s3 := []Student{s, s2}
arr := [3]int{1, 2, 3}
// range是一个函数,也可以写成 for i, v := range (arr) {
// 将arr遍历然后返回给v,所以在range内修改arr的值,不会影响原数据
for i, v := range arr {
arr[0] = 10
fmt.Println("range", i, v)
}
// 同样的修改v的值也不会影响原数据
for _, v := range s3 {
v.age = 99
fmt.Println("range", v.age)
}
fmt.Println(arr)
fmt.Println(s3)
}
无论是普通for循环,还是range迭代,其定义的局部变量都会重复使用
func main() {
str := [3]string{"a", "b", "c"}
for i, s := range str {
println(&i, &s)
}
}
输出:
0x14000062ee0 0x14000062ef8
0x14000062ee0 0x14000062ef8
0x14000062ee0 0x14000062ef8
如果range调用函数,函数只会被执行一次
func data() []int {
fmt.Println("初始化")
return []int{10, 20, 30}
}
func main() {
for i, x := range data() {
fmt.Println(i, x)
}
}
输出:
初始化
0 10
1 20
2 30
跳转控制语句break:
- 跳转控制语句
break
用在循环语句中跳出当前循环,执行循环后面的语句,可以在switch、for中使用 - 多重循环时默认跳出最近的循环,在循环嵌套中可以使用关键字
label
标记要跳出的位置
演示:
func main() {
for i := 1; i <= 5; i++ {
if i == 3 {
break
}
fmt.Println(i) // 结果是1、2 break会直接跳出for循环
}
}
计算100以内的偶数和,当偶数和大于100时停止循环并打印出当前i的值
func main() {
sum := 0
for i := 0; i < 100; i++ {
if i%2 == 0 {
sum += i
if sum > 100 {
fmt.Println("sum>100时,i=", i)
break
}
}
}
}
输出:
sum>100时,i= 20
指定跳转:
func main() {
lable: // 要跳过的代码前
要跳过的代码
break lable//要跳过的代码后的位
}
多重循环,内循环为2时结束全部循环
func main() {
label:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
break label
}
fmt.Println(j)
}
}
}
输出:
0
1
跳转控制语句continue:
跳转控制语句(continue):
满足条件后,跳过本次循环,继续下次循环,基于条件控制, 在循环内部使用,for可以用注意:
continue只能在循环中进行使用!- 在多重循环中可以使用标号
label
跳出循环
判断5以内的奇数并打印
func main() {
for i := 1; i <= 5; i++ {
if i == 2 {
continue
}
fmt.Println(i) // 结果是1、3、4、5 continue会跳过2,执行后面的
}
}
多重循环时判断是否等于2,等于2时跳过当前循环,继续下一次循环
func main() {
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 2 {
continue
}
fmt.Print(j)
}
}
}
输出:
010101
跳转控制语句(return):
retur表示终止函数或方法
func main() {
// return // 放在这里等于是结束函数
for i := 1; i <= 5; i++ {
if i == 3 {
break
}
fmt.Println("return前")
return // 放在这里是结束循环
fmt.Println("return后")
fmt.Println(i)
}
}
输出:
return前
跳转控制语句(goto)
跳转控制语句(goto):
转移到指定的行,goto一般配合条件判断使用,可以用来做条件转移,跳出循环等操作但是,在结构化程序设计中一般不主张使用 goto语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。
goto格式:
goto label
...
label : statement
演示:
func main() {
goto label // 跳过123,执行45
fmt.Println(1)
fmt.Println(2)
fmt.Println(3)
label:
fmt.Println(4)
fmt.Println(5)
}
如果向后面跳,会死循环
func main() {
label:
fmt.Println("走我了吗")
goto label
}
不能跳到其他函数或内部代码块
func main() {
goto loop // 未解析的标签 'loop'
goto test // 未解析的标签 'test'
for i := 0; i < 5; i++ {
loop: // 未使用的标签 'loop'
fmt.Println("goto03...")
}
}
func gotoTest() {
test: // 未使用的标签 'test'
}
循环嵌套
循环嵌套也可以说是多重循环,就是在一个循环体里面嵌入另一个循环
打印乘法口诀表案例:
func forDemo6() {
for i := 1; i <= 9; i++ { // 外循环控制行
for j := 1; j <= i; j++ { // 内循环控制列
fmt.Printf("%d*%d=%d ", j, i, j*1)
}
fmt.Print("\n")
}
}
输出结果:
1*1=1
1*2=1 2*2=2
1*3=1 2*3=2 3*3=3
1*4=1 2*4=2 3*4=3 4*4=4
1*5=1 2*5=2 3*5=3 4*5=4 5*5=5
1*6=1 2*6=2 3*6=3 4*6=4 5*6=5 6*6=6
1*7=1 2*7=2 3*7=3 4*7=4 5*7=5 6*7=6 7*7=7
1*8=1 2*8=2 3*8=3 4*8=4 5*8=5 6*8=6 7*8=7 8*8=8
1*9=1 2*9=2 3*9=3 4*9=4 5*9=5 6*9=6 7*9=7 8*9=8 9*9=9