6.Go流程控制

前言

前面我们写的程序都是从第一行开始执行,一直执行到末尾,一行一行的顺序执行下来,这种执行结构叫顺序执行结构。

GO语言除了有顺序结构,还有选择结构,循环结构。

  • 顺序结构:程序按顺序执行,不发生跳转。
  • 选择结构:依据是否满足条件,有选择的执行相应功能。
  • 循环结构:依据条件是否满足,循环多次执行某段代码。

下面先讲解选择结构:

1:选择结构

(1)生活中的判断场景

选择结构我们也称为判断结构。生活中的关于判断的场景也非常多,如下:

:如果跪键盘的时间大于60分钟,那么媳妇奖励我晚饭不用做了。


6.Go流程控制_软件测试

img

火车站安检

6.Go流程控制_switch_02


img

(2)开发中的判断场景

密码判断

6.Go流程控制_软件测试_03


img

重要日期判断

if今天是周六或者周日{
约妹子
}

if今天是情人节{
买玫瑰
}

if今天发工资{
先还信用卡的钱

if有剩余{
又可以happy了,O(∩_∩)O哈哈~
}else{
噢,no。。。还的等30天
}

}

小总结:

如果某些条件满足,才能做某件事情,而不满足时不允许做,这就是所谓的判断

1.1 if 结构

在编程中实现选择判断结构就是用if

if结构基本语法

if 条件判断{
代码语句
}

条件判断如果为真(true),那么就执行大括号中的语句,如果为假(false),就不执行大括号中的语句,(大家可以想一下,什么样的表达式返回的结果要么为true,要么为false),继续执行if结构后面的代码

具体案例如下:

var age int = 26
var b bool
b = age > 18
if b {
fmt.Println("我已经成年了")
}

上面的程序可以进行简化:

var age int = 26
if age > 18 {
fmt.Println("我已经成年了")
}

条件不满足时不执行

var age int = 16
if age > 18 {
fmt.Println("我已经成年了")
}

GO语言相比其它语言要灵活很多,下面我们看一下if的另外一种语法格式

// if 支持1个初始化语句,初始化语句和判断条件以分号分隔
if a := 10; a == 10 { // 条件为真,执行 {} 语句
fmt.Println("a == 10")
}

练习:让用户输入用户名和密码,如果用户名为admin,密码为mypass,则提示登录成功

package main

import "fmt"

func main() {

// 练习: 让用户输入用户名和密码,如果用户名为admin,密码为mypass,则提示登录成功
var userName string
var userPwd string

fmt.Println("请输入用户名: ")
fmt.Scan(&userName)

fmt.Println("请输入用户的密码:")
fmt.Scan(&userPwd)

if userName == "admin" && userPwd == "mypass" {
fmt.Println("登录成功")
}else {
fmt.Println("用户名和密码错误")
}
}

执行如下:

F:\goProject\go-pratice\05_流程控制>go run 01_if结构.go
请输入用户名:
admin
请输入用户的密码:
mypass
登录成功

F:\goProject\go-pratice\05_流程控制>go run 01_if结构.go
请输入用户名:
admin
请输入用户的密码:
123
用户名和密码错误

1.2 if else结构

想一想:在使用if的时候,它只能做到满足条件时要做的事情。那万一需要在不满足条件的时候,做某些事,该怎么办呢?

例如:小赵的考试成绩大于90(含)分,那么爸爸奖励他100元钱,否则的话,爸爸就让小赵跪方便面。

有同学可能会想,这道题用​​if​​结构也可以实现。如下所示:

package main

import "fmt"

func main() {
//小赵的考试成绩大于等于90分,那么爸爸奖励他100元钱,
//否则的话,爸爸就让小赵跪方便面

var score float64
fmt.Println("输入小赵的考试成绩:")
fmt.Scan(&score)

if score >= 90 {
fmt.Println("奖励100元")
}
if score < 90 {
fmt.Println("跪方便面")
}

}

虽然以上代码可以实现,但是比较麻烦,我们可以使用更简单的方式:if else

结构如下:

if 条件判断{

代码语句1

}else{

代码语句2

}

首先先执行​​if​​​后面的条件判断,如果条件判断成立(结果为真),执行​​if​​​后面的代码语句1,代码语句1执行完成后,表示整个​​if---else--​​结构结束了(else后面的代码语句2不会执行),继续执行后面的代码。

如果​​if​​​后面的条件判断不成立也就是结果为假,那么​​if​​​后面的代码语句1不会被执行,这时会执行​​else​​​后面的代码语句2,执行完后,表示整个​​if—else—​​结构执行结束了,再执行后续的代码。

下面我们通过​​if---else—​​结果完成上面的案例。

package main

import "fmt"

func main() {
//小赵的考试成绩大于等于90分,那么爸爸奖励他100元钱,
//否则的话,爸爸就让小赵跪方便面

var score float64
fmt.Println("输入小赵的考试成绩:")
fmt.Scan(&score)

if score >= 90 {
fmt.Println("奖励100元")
} else {
fmt.Println("跪方便面")
}

}

执行如下:

F:\goProject\go-pratice\05_流程控制>go run 02_if_else结构.go
输入小赵的考试成绩:
98
奖励100元

F:\goProject\go-pratice\05_流程控制>go run 02_if_else结构.go
输入小赵的考试成绩:
78
跪方便面

1.3 if 嵌套

我们上面的案例中,使用的是​​if-else​​​的基本结构,其实​​if-else​​结构还可以进行嵌套使用。

例如:输入公交卡当前的余额,只要超过2元,就可以上公交车;如果空座位的数量大于0,就可以坐下

package main

import "fmt"

func main() {

// 例如:输入公交卡当前的余额,只要超过2元,就可以上公交车;如果空座位的数量大于0,就可以坐下
var money float64
fmt.Println("请输入公交卡钱数:")
fmt.Scanf("%f\n", &money) // 注意:这里Scanf函数必须加上\n, 否则第二个Scanf不起作用

if money >= 2 {
var seat_count int // 注意:该变量的定义位置,用到时定义赋值,节省内存空间
fmt.Println("请输入空座位的数量:")
fmt.Scanf("%d", &seat_count)
if seat_count > 0 {
fmt.Println("请坐")
} else {
fmt.Println("不好意思,您只能站着了!")
}
} else {
fmt.Println("余额不足")
}
}

执行如下:

F:\goProject\go-pratice\05_流程控制>go run 03_if_嵌套.go
请输入公交卡钱数:
3
请输入空座位的数量:
1
请坐

F:\goProject\go-pratice\05_流程控制>go run 03_if_嵌套.go
请输入公交卡钱数:
3
请输入空座位的数量:
0
不好意思,您只能站着了!

F:\goProject\go-pratice\05_流程控制>go run 03_if_嵌套.go
请输入公交卡钱数:
1
余额不足

以上案例在if中嵌套了​​if-else​​​结构,同理在​​else​​​也可以嵌套​​if-else​​结构,这个要根据实际情况确定。下面我们看如下题目:

(1)对学员的结业考试成绩评测(大家考虑用if好还是用if-else好)

成绩>=90 :A    
90>成绩>=80 :B
80>成绩>=70 :C
70>成绩>=60 :D
成绩<60 :E

我们先使用if来实现上面的问题:

package main

import "fmt"

func main() {
fmt.Println("请输入考试成绩:")
var score int
fmt.Scanf("%d", &score)
if score >= 90 {
fmt.Println("A")
}
if score < 90 && score >= 80 {
fmt.Println("B")
}
if score < 80 && score >= 70 {
fmt.Println("C")
}
if score < 70 && score >= 60 {
fmt.Println("D")
} else { // 注意:else 的问题
fmt.Println("E")
}
}

执行如下:

F:\goProject\go-pratice\05_流程控制>go run 04_if_嵌套.go
请输入考试成绩:
90
A
E

F:\goProject\go-pratice\05_流程控制>go run 04_if_嵌套.go
请输入考试成绩:
80
B
E

F:\goProject\go-pratice\05_流程控制>go run 04_if_嵌套.go
请输入考试成绩:
60
D

上面的代码我们发现最后都会输出“E”,为什么呢?

这是因为最后一个 if-else 语句造成的,只要  if score < 70 && score >= 60 不成立,那么就会执行 else ,输出 “E”。

但是实际上,我们不希望在 score >= 90 的情况,不输出 “E”

解决方案如下:

6.Go流程控制_switch_04


image-20210423080917238

测试执行如下:

F:\goProject\go-pratice\05_流程控制>go run 04_if_嵌套.go
请输入考试成绩:
90
A

F:\goProject\go-pratice\05_流程控制>go run 04_if_嵌套.go
请输入考试成绩:
80
B

F:\goProject\go-pratice\05_流程控制>go run 04_if_嵌套.go
请输入考试成绩:
60
D

F:\goProject\go-pratice\05_流程控制>go run 04_if_嵌套.go
请输入考试成绩:
50
E

(2)下面我们来使用if-else 结构来解决上面的问题

案例演示如下:

package main

import "fmt"

func main() {
fmt.Println("请输入考试成绩:")
var score int
fmt.Scanf("%d", &score)
if score >= 90 {
fmt.Println("A")
} else {
// 所有小于90的分数都执行else,所以需要在else中继续判断(if-else结构的嵌套)
//if score < 90 && score >= 80 {
if score >= 80 {
fmt.Println("B")
} else {
//if score < 80 && score >= 70 {
if score >= 70 { // 同理这里也不需要对 < 80 进行判断
fmt.Println("C")
} else {
//if score < 70 && score >= 60 {
if score >= 60 {
fmt.Println("D")
} else {
fmt.Println("E")
}
}
}

}

}

上面的代码虽然满足了我们的需求,但是嵌套的代码非常多,可读性比较差,我们在以后的编程工作中尽量避免这种多重嵌套。

通过这道题,我们发现在这种多条件判断应用的场景中不太适合通过 if(适合一种条件判断的情况)或者是if-else(适合两种条件判断的情况或者是判断条件不是很多的场景)进行判断。

上面的题目更好的方法:if-else if结构。

1.4  if-else if 结构

基本语法如下:

if 条件判断{
要执行的代码段
}else if 条件判断{
要执行的代码段
}else if 条件判断{
要执行的代码段
}else if 条件判断{
要执行的代码段
}else{
要执行的代码段
}

通过以上的语法格式我们发现,可以写很多的else if结构。

具体的执行过程:

  • 程序首先判断第一个if所带的小括号中的判断条件,如果条件成立,也就是返回一个true,则执行该if所带的大括号中的代码,执行完成后,立即跳出if else-if结构。
  • 如果第一个if所带的判断条件不成立,也就是返回一个false,则继续向下进行判断,依次的判断每一个if所带的判断条件,如果成立,就执行该if所带的大括号中的代码,如果不成立,则继续向下判断,
  • 如果每个if所带的判断条件都不成立,就看当前这个if else-if结构中是否存在else。
  • 如果有else的话,则执行else中所带的代码,如果没有else,则整个 if-else if什么都不做。else可以省略。

下面我们使用该结构完成上面的案例:

package main

import "fmt"

func main() {
fmt.Println("请输入考试成绩:")
var score int
fmt.Scanf("%d", &score)
if score >= 90 {
fmt.Println("A")
} else if score >= 80 {
fmt.Println("B")
} else if score >= 70 {
fmt.Println("C")
} else if score >= 60 {
fmt.Println("D")
} else {
fmt.Println("E")
}
}

通过以上代码,我们发现if-else if 结构在进行多条件判断时确实比if, if-else(嵌套)要方便很多,并且结构清晰,阅读性比较强。

(1)练习:提示用户输入密码,如果密码是“88888”则提示正确,否则要求再输入一次,如果密码是“88888”则提示正确,否则提示错误,程序结束。

package main

import "fmt"

func main() {
// (1)练习:
// 提示用户输入密码,如果密码是“88888”则提示正确,
// 否则要求再输入一次,如果密码是“88888”则提示正确,否则提示错误,程序结束。
var pwd string
fmt.Println("请输入密码")
fmt.Scanf("%s\n", &pwd)
if pwd == "88888" {
fmt.Println("密码输入正确")
} else {
fmt.Println("密码错误,请重新输入!!")
fmt.Scanf("%s", &pwd)
if pwd == "88888" {
fmt.Println("密码第二次输入正确")
} else {
fmt.Println("密码错误!!")
}
}
}

执行如下:

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入密码
66
密码错误,请重新输入!!
88888
密码第二次输入正确

(2) 练习:提示用户输入用户名,然后再提示输入密码,如果用户名是“admin”并且密码是“88888”,则提示正确,否则,如果用户名不是admin还提示用户用户名不存在,如果用户名是admin则提示密码错误。

// (2) 练习:
//提示用户输入用户名,然后再提示输入密码,如果用户名是“admin”并且密码是“88888”,则提示正确,
//否则,如果用户名不是admin还提示用户用户名不存在,如果用户名是admin则提示密码错误。
var name string
var pwd string
fmt.Println("请输入用户名: ")
fmt.Scanf("%s\n", &name)
fmt.Println("请输入密码:")
fmt.Scanf("%s", &pwd)
// 如果用户名是“admin”并且密码是“88888”,则提示正确
if name == "admin" && pwd == "88888" {
fmt.Println("登录成功")
} else if name == "admin" && pwd != "88888"{
// 如果用户名是admin则提示密码错误
fmt.Println("密码错误")
} else {
fmt.Println("用户名和密码都错误")
}

执行如下:

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入用户名:
hello
请输入密码:
hell
用户名和密码都错误

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入用户名:
admin
请输入密码:
123
密码错误

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入用户名:
admin
请输入密码:
88888
登录成功

用于该题的判断条件比较多,所以这里使用的是if-else if结构。

(3) 练习:提示用户输入年龄,如果大于等于18,则告知用户可以查看,如果小于10岁,则告知不允许查看,如果大于等于10岁并且小于18,则提示用户是否继续查看(yes、no),如果输入的是yes则提示用户请查看,否则提示"退出,你放弃查看"。

首先我们分析一下该题的条件:

  • 第一种情况:年龄>=18
  • 第二种情况:年龄<10
  • 第三种情况:年龄>=10&&<18,如果满足该条件,则继续判断用户输入的内容是“yes”还是”no”

根据以上分析,使用if-else if 结构比较容易实现。具体案例展示如下:

// (3) 练习:提示用户输入年龄,如果大于等于18,则告知用户可以查看,
//如果小于10岁,则告知不允许查看,
//如果大于等于10岁并且小于18,则提示用户是否继续查看(yes、no),
//如果输入的是yes则提示用户请查看,否则提示"退出,你放弃查看"。
var age int
fmt.Println("请输入年龄:")
fmt.Scanf("%d\n", &age)
if age >= 18 {
// 如果大于等于18,则告知用户可以查看
fmt.Println("可以查看信息")
} else if age < 10 {
//如果小于10岁,则告知不允许查看,
fmt.Println("不允许查看")
} else if age >= 10 && age < 18{
//如果大于等于10岁并且小于18,则提示用户是否继续查看(yes、no)
var input string
fmt.Println("是否继续查看(yes、no)")
fmt.Scanf("%s", &input)
if input == "yes" {
fmt.Println("用户请查看")
} else {
fmt.Println("退出,你放弃查看")
}
}

执行如下:

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入年龄:
16
是否继续查看(yes、no)
yes
用户请查看

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入年龄:
no
不允许查看

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入年龄:
18
可以查看信息

F:\goProject\go-pratice\05_流程控制>go run 07_if_else_if.go
请输入年龄:
9
不允许查看

总结:我们通过前面的案例讲解,大家应该能够总结出if结构,if-else结构和if-else if结构应用的场景.

  • if结构适合:一种的判断
  • if-else结构适合:两种情况的判断
  • if-else if 结构适合: 多种情况判断,并且判断都是对区间中的数据进行判断(例如:考试成绩)

1.5  switch 结构

下面我们开始讲解选择中的另外一个结构就是switch结构。

在讲解switch结构之前,我们先来看如下问题:

李四的年终工作评定,如果定为A级,则工资涨500元,如果定为B级,则工资涨200元,如果定为C级,工资不变,如果定为D级工资降200元,如果定为E级工资降500元.

设李四的原工资为5000,请用户输入李四的评级,然后显示李四来年的工资.

大家看到如上题目,肯定想到的是用 ​​if-else if​​结构来实现,那么具体案例实现如下:

package main

import "fmt"

func main() {
/**
李四的年终工作评定,
- 如果定为A级,则工资涨500元,
- 如果定为B级,则工资涨200元,
- 如果定为C级,工资不变,
- 如果定为D级工资降200元,
- 如果定为E级工资降500元.

设李四的原工资为5000,请用户输入李四的评级,然后显示李四来年的工资.
*/
var salary int = 5000 // 原定工资
var level string

fmt.Println("请输入李四的年终评定:")
fmt.Scanf("%s", &level)

if level == "A" {
// 如果定为A级,则工资涨500元
salary += 500
} else if level == "B" {
// 如果定为B级,则工资涨200元
salary += 200
} else if level == "C" {
// 如果定为C级,工资不变
} else if level == "D" {
// 如果定为D级工资降200元
salary -= 200
} else if level == "E" {
// 如果定为E级工资降500元
salary -= 500
} else {
fmt.Println("输入错误,程序推迟!!")
}

fmt.Println("李四来年的工资是: ", salary)

}

虽然以上代码实现了我们的需求,但是我们发现了一个问题,如果输入其它字符(例如:输入字符T),我们发现最终的结果不仅输出了“输入错误,程序退出”,同时还输出了“李四来年的工资是:5000”。如果输入错误了,这句话是不应该输出的,那么应该怎样进行处理呢?

package main

import "fmt"

func main() {
/**
李四的年终工作评定,
- 如果定为A级,则工资涨500元,
- 如果定为B级,则工资涨200元,
- 如果定为C级,工资不变,
- 如果定为D级工资降200元,
- 如果定为E级工资降500元.

设李四的原工资为5000,请用户输入李四的评级,然后显示李四来年的工资.
*/
var salary int = 5000 // 原定工资
var level string

fmt.Println("请输入李四的年终评定:")
fmt.Scanf("%s", &level)

var flag bool = true // 设置是否打印工资的信息

if level == "A" {
// 如果定为A级,则工资涨500元
salary += 500
} else if level == "B" {
// 如果定为B级,则工资涨200元
salary += 200
} else if level == "C" {
// 如果定为C级,工资不变
} else if level == "D" {
// 如果定为D级工资降200元
salary -= 200
} else if level == "E" {
// 如果定为E级工资降500元
salary -= 500
} else {
flag = false // 当错误,则不打印工资信息
fmt.Println("输入错误,程序推迟!!")
}

// 当输入正确,才打印工资信息
if flag {
fmt.Println("李四来年的工资是: ", salary)
}

}

通过上面的代码,我们实际上是定义了一个bool类型的变量 flag,默认值为true,当输入评定级别错误时,将其改为false.最后在输出工资时,做了判断,如果条件成立表示输入了正确的评定级别,所以输出对应的工资,否则不输出工资。(这种技巧,需要大家好好体会一下)

我们前面在讲解if-else if结构时讲过,该结构适合什么场合:1.多条件判断,2:区间性的数据判断。但是我们看一下该案例,是否是对区间性的数据进行判断呢?不是,而是定值判断,也就是对一个固定值的判断。

对这种固定值的判断推进使用switch-case结构。

(1) switch-case结构语法如下:

switch 变量或者表达式的值{
case 值1:
要执行的代码
case 值2:
要执行的代码
case 值3:
要执行的代码
………………………………
default:
要执行的代码
}

switch-case结构的执行流程:

程序执行到switch处,首先将变量或者表达式的值计算出来,然后拿着这个值依次跟每个case后面所带的值进行匹配,一旦匹配成功,则执行该case所带的代码,执行完成后,跳出switch-case结构。如果,跟每个case所带的值都不匹配。就看当前这个switch-case结构中是否存在default,如果有default,则执行default中的语句,如果没有default,则该switch-case结构什么都不做。

基本案例演示如下:

package main

import "fmt"

func main() {
var score int = 30
switch score {
case 90:
fmt.Println("优秀")
case 80:
fmt.Println("良好")
case 70:
fmt.Println("一般")
case 60:
fmt.Println("及格")
default:
fmt.Println("不及格")
}
}

GO语言中switch-case结构中,case后面默认自带break(终止程序执行),这是与其它语言不同的地方。

另外一种语法格式如下:

// 另外一种语法格式如下:
switch score := 78; score { // 初始化变量 score 的同时,将其设置为 case 变量
case 90:
fmt.Println("优秀")
case 80:
fmt.Println("良好")
case 70:
fmt.Println("一般")
case 60:
fmt.Println("及格")
default:
fmt.Println("不及格")
}

注意:某个case 后面跟着的代码执行完毕后,不会再执行后面的case,而是跳出整个switch结构, 相当于每个case后面都跟着break(终止),但是如果我们想执行完成某个case后,强制执行后面的case,可以使用​​fallthrough​​。

下面我们用switch-case结构来实现上面的案例,示例如下:

// fallthrough
/**
李四的年终工作评定,
- 如果定为A级,则工资涨500元,
- 如果定为B级,则工资涨200元,
- 如果定为C级,工资不变,
- 如果定为D级工资降200元,
- 如果定为E级工资降500元.

设李四的原工资为5000,请用户输入李四的评级,然后显示李四来年的工资.
*/
var salary int = 5000 // 原定工资
var level string

fmt.Println("请输入李四的年终评定:")
fmt.Scanf("%s", &level)

var flag bool = true // 设置是否打印工资的信息

switch level {
case "A":
// 如果定为A级,则工资涨500元
salary += 500
case "B":
// 如果定为B级,则工资涨200元
salary += 200
case "C":
// 如果定为C级,工资不变
fallthrough
case "D":
// 如果定为D级工资降200元
salary -= 200
case "E":
// 如果定为E级工资降500元
salary -= 500
default:
flag = false // 当错误,则不打印工资信息
fmt.Println("输入错误,程序推迟!!")
}

// 当输入正确,才打印工资信息
if flag {
fmt.Println("李四来年的工资是: ", salary)
}

1.6 if-else if与switch的比较

其实通过上面的案例,我们发现switch能够实现的,我们用if-else if也可以实现,那么反过来呢,if-else if能实现的,我们使用switch能否实现呢?接下来将我们前面用if-else if实现的“考试成绩评定”这道题用switch来实现。

fmt.Println("请输入考试成绩:")
var score int
fmt.Scanf("%d", &score)
switch { // 这里没有写条件
case score >= 90: // 在case写判断语句
fmt.Println("A")
case score >= 80:
fmt.Println("B")
case score >= 70:
fmt.Println("C")
case score >= 60:
fmt.Println("D")
default:
fmt.Println("E")
}

总结:

  • 相同点:都可以实现多分支结构
  • 不同点(根据个人习惯进行选择):
    if-else if: 可以处理范围
    switch: 一般用于等值比较

下面我们通过一个练习题,将if-else和switch结构进行综合应用

练习:请用户输年份,再输入月份,输出该月的天数.(结合之前如何判断闰年来做)

package main

import "fmt"

func main() {
//请用户输年份,再输入月份,输出该月的天数.
var year int //表示年份
var month int //表示月份
var day int

fmt.Println("请输入年份")
fmt.Scanf("%d\n", &year)
fmt.Println("请输入月份")
fmt.Scanf("%d", &month)

//判断月份的取值范围
if month >= 1 && month <= 12 {
switch month{
case 1:
fallthrough
case 3:
fallthrough
case 5:
fallthrough
case 7:
fallthrough
case 8:
fallthrough
case 10:
fallthrough
case 12:
day = 31
case 2: //需要判断是否为闰年
if (year%400==0) || (year%4==0 && year%100!=0){
day = 29
} else{
day = 28
}
default:
day = 30
}

fmt.Printf("%d年%d月共%d天", year, month, day)
} else {
fmt.Println("月份输入错误!!")
}
}

通过上面的案例,我们发现switch结构和if-else结构是可以结合来使用的,可以根据具体的问题具体分析,灵活来应用。

2:循环结构

2.1 循环概念

所谓的循环就是重复的做同一件事情,我们先从生活的角度来理解一下循环。

6.Go流程控制_软件测试_05


img

打印100份试卷

李四这次考试又粗心了,爸爸让他写1000遍“下次考试一定要细心”.

在编程中,我们也会经常遇到循环的问题,例如:

跟媳妇承认错误,说一万遍"媳妇儿,我错了"

fmt.Println("媳妇儿,我错了")

fmt.Println("媳妇儿,我错了")

fmt.Println("媳妇儿,我错了")

…………………………………写一万遍 fmt.Println("媳妇儿,我错了")

2.2 基本语法结构

在GO语言中,我们有专门实现这种循环的结构就是for结构(GO语言中只有for循环结构,没有while,do-while结构),

基本语法结构如下:

for 表达式1;表达式2;表达式3{
循环体
}
  • 表达式1:定义一个循环的变量,记录循环的次数
  • 表达式2:一般为循环条件,循环多少次
  • 表达式3:一般为改变循环条件的代码,使循环条件终有一天不再成立
  • 循环体:重复要做的事情。

下面我们用for循环结构输出10遍“媳妇儿,我错了”。

func main() {
// 用for循环结构输出10遍“媳妇儿,我错了”
var i int
for i = 1; i <= 10; i++ {
fmt.Println("媳妇儿,我错了")
}
}

以上代码执行的顺序:

  • 首先执行表达式1(​​i = 1​​)进行初始化,然后执行表达式2(​​i <= 10​​),判断循环条件是否成立,如果表达式2返回的结果为true,则执行循环体。
  • 当执行完循环体后,执行表达式3(​​i++​​),然后执行表达式2(这时不会在执行表达式1)继续判断循环条件是否成立,
    如果成立则继续执行循环体,如果不成立,则跳出for循环。

思考:将上面的代码中,变量i的初始值赋值为0,那么表达式2怎样修改?

我们也可以将语法进行简化如下:

// 用for循环结构输出10遍“媳妇儿,我错了”
//var i int
for i := 0; i < 10; i++ {
fmt.Println("媳妇儿,我错了")
}

2.3 练习

(2.3.1)求1—100之间所有的整数之和。

// (2.3.1)求1—100之间所有的整数之和。
var sum int // 定义一个变量,存储累加的和
for i := 1; i <= 100; i++ {
sum += i
}
fmt.Println("累加的和为: ", sum)

执行如下:

累加的和为:  5050

(2.3.2)求1—100之间的耦合之和

// (2.3.2)求1—100之间的耦合之和
var sum int // 定义一个变量,存储累加的和
for i := 1; i <= 100; i++ {
if i%2 == 0 {
sum += i
}
}
fmt.Println("求1—100之间的耦合之和: ", sum)

执行如下:

求1—100之间的耦合之和:  2550

(2.3.3)输入班级人数,然后依次输入学员成绩,计算班级学员的平均成绩和总成绩

分析:首先让用户输入班级的人数,例如10人

循环变量:初始值为1

循环条件:循环的次数小于班级人数

循环体:提示用户输入学生的成绩,然后接收,接收完成后,累加到总成绩中。

具体案例如下:

// (2.3.3)输入班级人数,然后依次输入学员成绩,计算班级学员的平均成绩和总成绩
var count int
var score float64
var sum float64
fmt.Println("请输入班级人数:")
fmt.Scanf("%d\n", &count)
// 通过循环统计综合
for i := 1; i <= count; i++ {
fmt.Printf("请输入%d学生的成绩: ", i)
fmt.Scanf("%f\n", &score)
sum += score
}
fmt.Printf("班级总人数为: %d, 总成绩为: %f, 平局成绩: %f", count, sum, sum/float64(count))

执行如下:

请输入班级人数:
3
请输入1学生的成绩: 99
请输入2学生的成绩: 65
请输入3学生的成绩: 89
班级总人数为: 3, 总成绩为: 253.000000, 平局成绩: 84.333333

(2.3.4)2006年培养学员80000人,每年增长25%,请问按此增长速度,到哪一年培训学员人数将达到20万人

分析:循环条件:学员人数>20万人时,结束整个循环,否则继续循环。(先将循环条件分析清楚,并且写完代码,然后在分析循环体)

循环体:对年份进行累加

// (2.3.4)2006年培养学员80000人,每年增长25%,请问按此增长速度,到哪一年培训学员人数将达到20万人
var people float64
var year int = 2006
for people = 80000; people <= 200000 ; people = people * 1.25 {
year += 1
}
fmt.Printf("到%d年培训学院人数将达到20万人", year)

执行如下:

到2011年培训学院人数将达到20万人

注意:第三个表达式的变化。

(2.3.5)找出100-999间的水仙花数

分析:水仙花数指的就是 这个百位数字的,百位的立方 + 十位的立方 + 个位的立方 == 当前这个百位数字

例如: 153这个数字 百位数为1, 十位数为5,个位数为3

那么1的立方是1,  5的立方是125,  3的立方是27。

那么1+125+27正好是153

所以这道题的关键是我们怎样获取某个三位数字中的百位,十位,个位。

方法如下:

百位:153/100
十位:153%100/10
个位:153%10

具体案例如下:

// (2.3.5)找出100-999间的水仙花数
var h int // 百位数
var t int // 十位数
var u int // 个位数
for i := 100; i <= 999; i++ {
h = i / 100
t = i % 100 / 10
u = i % 10
if (h*h*h)+(t*t*t)+(u*u*u) == i {
fmt.Println("水仙花数有:", i)
}
}

执行如下:

水仙花数有: 153
水仙花数有: 370
水仙花数有: 371
水仙花数有: 407

2.4 跳转语句

关于GO语句中的跳转语句,有break,continue,goto(与函数结合使用)

下面我们先来讲解break.

根据前面的案例,我们发现,循环必须指定循环条件,在满足循环条件的时候执行循环,如果不满足循环的条件,可以跳出整个循环。但是如果,我们没有指定循环条件,那么循环就成了死循环,所谓的死循环指的就是一直循环,跳不出来了。

怎样构建死循环呢?语法如下:

// 死循环
for {
fmt.Println("死循环.....")
}

执行如下:

死循环.....
死循环.....
死循环.....
死循环.....
死循环.....
死循环.....
死循环.....
...

死循环(无限循环)的语法非常简单,就是什么循环条件也没有写。

下面我们来看一下,关于死循环的应用场景

(2.4.1)案例:要求用户输入用户名和密码,只要不是admin、888888就一直提示用户名,密码错误,请重新输入。

分析:该题我们怎样构建循环条件呢?

按照我们以前的做法,很难构建循环条件,那么我们可以使用死循环来做,但是,我们要在用户输入正确的用户名和密码的时候跳出整个循环,那么我们应该怎样强制的跳出死循环呢?我们可以使用break关键字。

break的作用就是跳出本次循环

案例演示如下:

// (2.4.1)案例:要求用户输入用户名和密码,只要不是admin、888888就一直提示用户名,密码错误,请重新输入。
var userName string
var userPwd string
for {
fmt.Println("请输入用户名: ")
fmt.Scanf("%s\n", &userName)
fmt.Printf("请输入密码:")
fmt.Scanf("%s\n", &userPwd)
//判断用户名,密码输入是否正确
if userName == "admin" && userPwd == "888888" {
fmt.Println("登录成功")
break // 跳出循环
} else {
fmt.Println("用户名密码错误,请重新输入!!")
}
}

执行如下:

6.Go流程控制_java_06


image-20210426002350305

通过以上案例演示,我们发现当程序执行到break语句时,会跳出for循环。


思考: 现在将上面的题目的需求在改动一下,加上以下条件”用户名密码输入错误,最多输错3次,超过3次,提示输入错误信息次数太多,并且结束整个程序”,那么该程序怎样修改呢?

案例演示如下:

// (2.4.1)案例:要求用户输入用户名和密码,只要不是admin、888888就一直提示用户名,密码错误,请重新输入。
var userName string
var userPwd string
var count int // 记录错误次数
for {
fmt.Println("请输入用户名: ")
fmt.Scanf("%s\n", &userName)
fmt.Printf("请输入密码:")
fmt.Scanf("%s\n", &userPwd)
//判断用户名,密码输入是否正确
if userName == "admin" && userPwd == "888888" {
fmt.Println("登录成功")
break // 跳出循环
} else {
count++ // 输入错误,进行累加
if count >= 3 {
//当错误大于等于3次,则提示错误太多,停止循环
fmt.Println("输入错误次数太多!")
break // 跳出循环
}
fmt.Println("用户名密码错误,请重新输入!!")
}
}

执行如下:

6.Go流程控制_软件测试_07


image-20210426082902595

(2.4.2)老师问学生,这道题你会做了吗?如果学生答"会了(y)",则可以放学.如果学生不会做(n),则老师再讲一遍,再问学生是否会做了......

问题1:直到学生会为止,才可以放学.

问题2:直到学生会或老师给他讲了10遍还不会,都要放学

分析:这道题与上一道非常类似,大家可以自己思考做一下。

(2.4.3)循环录入5个人的年龄并计算平均年龄,如果录入的数据出现负数或大于100的数,立即停止输入并报错

分析: 定义一个变量来接收用户输入的年龄,同时还要定义一个变量来保存5个人的年龄之和。

然后大家思考一下,要解决该问题是否还要用死循环呢?不需要,因为这里已经规定了要输入5个人的年龄,所以我们可以循环5次

但是只要输入了负数或大于100的数,我们可以使用break强制终止程序。

// (2.4.3)循环录入5个人的年龄并计算平均年龄,如果录入的数据出现负数或大于100的数,立即停止输入并报错
var age int
var sum int
var b bool = true
for i := 1; i <= 5; i++ {
fmt.Printf("请输入第%d个人的年龄: \n", i)
fmt.Scanf("%d\n", &age)
if age < 0 || age > 100 {
fmt.Println("输入错误!!")
b = false
break
}
sum += age
}
if b {
fmt.Println("5个人的总年龄是", sum)
}

正确执行如下:

6.Go流程控制_java_08


image-20210426083804788

错误执行如下:

6.Go流程控制_软件测试_09


image-20210426083826723

(2.4.4)continue语句

前面我们已经讲解完成了break,下面我们来说一下continue语句。

continue的作用是:立即结束本次循环,判断循环条件,如果成立,则进入下一次循环,否则退出循环.

基本语法:

// continue语句
for i := 1; i <= 5; i++ {
if i == 2 {
continue
}
fmt.Println("i的值为:", i)
}

执行如下:

i的值为: 1
i的值为: 3
i的值为: 4
i的值为: 5

执行过程: 当i的值为1时,判断循环条件,满足循环条件(i<=5),进入循环体,执行if判断,发现条件不满足,不执行continue,直接打印,第一次循环结束,进入第二次循环,这时变量i的值为2, 满足循环条件,进入循环体,执行if判断,发现满足条件,执行continue,continue的作用:结束本次循环,也就是不在执行后面的代码(不管后面有多少行代码都不在执行),直接跳转到for,执行for循环的第三个表达式,让i的值进行加1操作,这时i变量的值变成3,判断一下是否满足循环条件,满足(i<=5),进入循环体,开始执行,以此类推。最终输出结果:1,3,4,5

(2.4.5)练习:用continue实现计算1到100(含)之间的除了能被7整除之外所有整数的和。(该题也可以使用其它方式来实现)

// (2.4.5)练习:用continue实现计算1到100(含)之间的除了能被7整除之外所有整数的和。(该题也可以使用其它方式来实现)
var sum int
for i := 1; i <= 100 ; i++ {
if i%7 == 0 {
continue
}
sum += i
}
fmt.Println(sum)

执行如下:

4315

(2.4.6)循环嵌套

我们在前面学习选择结构时,讲解过关于选择结构的嵌套,同理循环结构也有嵌套。

基本使用结构如下:

var i int
var j int
for i = 1; i <= 10; i++ {
for j = 1; j <= 10; j++ {

}
}

在屏幕上输出如下图所示的乘法口诀表

如图所示:

6.Go流程控制_java_10


image-20210426084706205

var i int
var j int
for i = 1; i <= 10; i++ {
for j = 1; j <= 10; j++ {
fmt.Printf("%d*%d=%d\t",i,j,i*j)
}
fmt.Println("")
}

输出以下结构的乘法口诀表:

6.Go流程控制_switch_11


image-20210426084819555

var i int
var j int
for i = 1; i <= 10; i++ {
for j = 1; j <= i; j++ {
fmt.Printf("%d*%d=%d\t",i,j,i*j)
}
fmt.Println("")
}

(2.4.7)输出以下图形

6.Go流程控制_python_12


image-20210426084913756

var i int
var j int
for i = 1; i <= 10; i++ {
for j = 1; j <= i; j++ {
fmt.Printf("*")
}
fmt.Println("")
}

注意:尽量不要多层嵌套,性能比较低。