Go_流程、跳转控制语详解

流程控制语句分类:

流程控制语句可以控制代码的执行顺序和条件

  1. 顺序结构:普通的代码,由上而下依次执行
  2. 分支结构(if, switch)
  3. 循环结构(for)

if语句:

条件表达式值必须是bool类型,不可省略括号,且左大括号不能另起一行

格式1:

if (关系表达式) {
    语句体;	
}

执行流程:

  1. 首先计算关系表达式的值
  2. 如果关系表达式的值为true就执行语句体
  3. 如果关系表达式的值为false就不执行语句体
  4. 继续执行后面的语句内容

if语句格式2:

if (关系表达式) {
    语句体1;	
} else {
    语句体2;	
}

执行流程:

  1. 首先计算关系表达式的值
  2. 如果关系表达式的值为true就执行语句体1
  3. 如果关系表达式的值为false就执行语句体2
  4. 继续执行后面的语句内容

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:
  		语句体
  }

执行流程:

  1. 首先计算出表达式的值
  2. 其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
  3. 最后,如果所有的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 ; ; {} // 死循环,只不过格式不同
}

格式解释:

  • 初始化语句: 用于表示循环开启时的起始状态,就是循环开始的时候什么样
  • 条件判断语句:用于表示循环反复执行的条件,就是判断循环是否能一直执行下去
  • 循环体语句: 用于表示循环反复执行的内容,就是循环反复执行的事情
  • 条件控制语句:用于表示循环执行中每次变化的内容,就是控制循环是否能执行下去

执行流程:

  1. 执行初始化语句
  2. 执行条件判断语句,看其结果是true还是false
    如果是false,循环结束
    如果是true,继续执行
  3. 执行循环体语句
  4. 执行条件控制语句
  5. 回到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 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzhuzhu.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值