Go语言の程序流程控制

程序流程控制介绍

在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句。

  1. 顺序控制
  2. 分支控制
  3. 循环控制

顺序控制

​ 程序从上到下逐行执行,中间没有任何判断和跳转。

​ 一个案例说明,必须下面的代码中,没有判断,也没有跳转,因此程序按照默认的流程执行,即顺序控制。

package main
import (
	"fmt"
)
func main(){
	var days int = 97
	var week int = days / 7
	var day int = days % 7
	fmt.Printf("%d个星期零%d天\n", week, day)

	var huashi float32 = 134.2
	var sheshi float32 = 5.0 / 9 * (huashi - 100)
	fmt.Printf("%v 对应的摄氏温度=%v \n", huashi, sheshi)
}
13个星期零6天
134.2对应的摄氏温度= 19 

程序控制的流程图

顺序控制举例和注意事项

​ Golang中定义变量时采用合法的前向引用。如:

func main(){
  var num1 int = 10 //声明了num1
  var num2 int = num1 + 20 //使用num1
  fmt.Println(num2)
}

错误形式:

func main(){
  var num2 int = num1 + 20 //使用num1
  var num1 int = 10 //声明num1 (❌)
  fmt.Println(num2)
}

分支控制

分支控制的基本介绍

分支控制就是让程序有选择执行。有下面三种形式

  1. 单分支
  2. 双分支
  3. 多分枝

单分支控制

  • 基本语法
if 条件表达式{
  执行代码块
}

说明:当条件表达式为true时,就会执行{}的代码。注意{}是必须有的,就算你只写一行代码。

  • 应用案例

编写一个程序,可以输入人的年龄,如果该同志的年龄大于 18 岁,则输出 “你年龄大 于 18,要对自己的行为负责!”。 需求—【分析】—>代码

func main() {
  var age int
  fmt.Println("请输入年龄:")
  fmt.Scanln(&age)
  
  if age > 18 {
    fmt.Println("你年龄大于18,要对自己的行为负责!")
  }
}
➜  main go run ./main.go
请输入年龄:
10
➜  main go run ./main.go
请输入年龄:
29
你年龄大于18,要对自己的行为负责!
➜  main 
  • 单分支的流程图

    流程图可以用图形方式来更加清晰的描述程序执行的流程。

  • 单分支的细节说明

if age := 20; age > 18{
  fmt.Println("你年龄大于18,要对自己的行为负责!")
}

双分支控制

  • 基本语法
if 条件表达式{
  执行代码块1
} else {
  执行代码块2
}

说明:当条件表达式成立,即执行代码块1,否则执行代码块2.{}也是必须有的。

  • 应用案例

编写一个程序,可以输入人的年龄,如果该同志的年龄大于 18 岁,则输出 “你年龄大于 18,要对 自己的行为负责!”。否则 ,输出”你的年龄不大这次放过你了.”

package main
import (
	"fmt"
)
func main() {
	var age int
	fmt.Println("请输入年龄:")
	fmt.Scanln(&age)
	
	if age > 18 {
	  fmt.Println("你年龄大于18,要对自己的行为负责!")
	} else {
		fmt.Println("你的年龄不大这次放过你了.")
	}
}
➜  main go run ./main.go
请输入年龄:
19
你年龄大于18,要对自己的行为负责!
➜  main go run ./main.go
请输入年龄:
12
你的年龄不大这次放过你了.
  • 双分支流程图的分析

  • 对双分支的总结
  1. 从上图看,条件表达式就是age>18
  2. 执行代码块1 就是 fmt.Prinltn(“你的年龄大于18”)…
  3. 执行代码块2 就是 fmt.Println(“你的年龄不大”)…
  4. 双分支只会执行其中的一个分支。

单分支和双分支的案例

  1. 对下列代码,若有输出,指出输出结果.
var x int = 4
var y int = 1
if (x > 2){
  if(y > 2){
    fmt.Println(x + y))
  }
  fmt.Println("hihihi")
}else{
  fmt.Println("x is =",x)
}
//输出结果是 hihihi
  1. 对下列代码,若有输出,指出输出结果.
var x int = 4
if x > 2
    fmt.Println("ok")
else
    fmt.Println("hello")
//没有{} 所以编译错误哦
  1. 对下列代码,若有输出,指出输出结果.
var x int = 4
if x > 2{
  fmt.Println("ok")
}
else {
  fmt.Println("hello")
}
//编译错误,因为else不能换行
  1. 对下列代码,若有输出,指出输出结果.
var x int = 4
if (x > 2){
  fmt.Println("ok")
}
else {
  fmt.Println("hello")
}
//输出ok 但是建议把if(x>2)写成if x > 2
  1. 编写程序,声明 2 个 int32 型变量并赋值。判断两数之和,如果大于等于 50,打印“hello world!
func main(){
  var n1 int32 = 10
  var n2 int32 = 50
  if n1 + n2 >=50 {
    fmt.Println("hello,world")
  }
}
  1. 编写程序,声明 2 个 float64 型变量并赋值。判断第一个数大于 10.0,且第 2 个数小于 20.0,打 印两数之和。
var n3 float64 = 11.0
var n4 float64 = 17.0
if n3 > 10.0 && n4 < 20.0 {
  fmt.Println("和=",(n3+n4))
}
  1. 定义两个变量 int32,判断二者的和,是否能被 3 又能被 5 整除,打印提示信息
var num1 int32 = 10
var num2 int32 = 5
if (num1 + num2) % 3 == 0 && (num1 + num2) % 5 == 0{
  fmt.Println("能被3又能被5整除")
}
  1. 判断一个年份是否是闰年,闰年的条件是符合下面二者之一:(1)年份能被4整除,但不能被100 整除;(2)能被 400 整除
var year int = 2019
if (year % 4 == 0 && year % 100 != 0)|| year % 400 == 0{
  fmt.Println(year, "是闰年!``")
}

多分支控制

  • 基本语法
if 条件表达式1 {
  执行代码块1
}else if{
  执行代码块2
}
...
else {
  执行代码块n
}
  • 说明:
  1. 多分支的判断流程如下:
    1. 先判断条件表达式1是否成立,如果为真,就执行代码块1
    2. 如果条件表达式1如果为假,就去判断条件表达式2是否成立,如果条件表达式2为真,就执行代码块2
    3. 以此类推
    4. 如果所有的条件表达式不成立,则执行else的语句块。
  2. else 不是必须的
  3. 多分支只能有一个执行入口。
  • 看一个多分支的流程图

  • 多分支的快速入门案例

岳小鹏参加 Golang 考试,他和父亲岳不群达成承诺: 如果:

​ 成绩为 100 分时,奖励一辆 BMW;

​ 成绩为(80,99]时,奖励一台 iphone7plus;

​ 当成绩为[60,80]时,奖励一个 iPad;

​ 其它时,什么奖励也没有。 请从键盘输入岳小鹏的期末成绩,并加以判断

func main(){
  var score int
  fmt.Print("请输入成绩:")
  fmt.Scanln(&score)
  if score == 100{
    fmt.Println("奖励BMW")
  }else if score > 80 && score <= 99 {
    fmt.Println("奖励一台iphone12 pro max")
  }else if score >= 60 && score <=80 {
    fmt.Println("奖励一个iPad")
  }else {
    fmt.Println("啥也没")
  }
}
  • 多分支的课堂练习

    案例演示2

func main(){
  var b bool = true
  if b == false {
    fmt.Println("a")
  } else if b{
    fmt.Println("b")
  } else if !b{
    fmt.Println("c")//c
  }else {
    fmt.Println("d")
  }
}
//输出结果是b
//如果写成b=flase;能编译通过吗?如果能,结果是?(不能通过,if的条件表达式不是赋值语句)

​ 案例演示3

package main
import (
	"fmt"
	"math"
)
func main() {
	var a float64 = 1.0
	var b float64 = 4.0
	var c float64 = 2.0

	m := b * b - 4 * a * c
	//多分支判断
	if m > 0 {
	  x1 := (-b + math.Sqrt(m)) / 2 * a
	  x2 := (-b - math.Sqrt(m)) / 2 * a
	  fmt.Printf("x1=%v x2=%v \n", x1, x2)
	}else if m == 0{
	  x1 := (-b + math.Sqrt(m)) / 2 * a
	  fmt.Printf("x1=%v\n", x1)
	}else {
	  fmt.Println("无解...")
	}
}
➜  main go run ./main.go
x1=-4%                                                                                           
➜  main go run ./main.go
x1=-0.5857864376269049 x2=-3.414213562373095%                                                    
➜  main go run ./main.go
x1=-0.5857864376269049 x2=-3.414213562373095 
➜  main 

​ 案例演示4

var height int32
var money float32
var handsome bool

fmt.Println("请输入身高(厘米)")
fmt.Scanln(&height)
fmt.Println("请输入财富(千万)")
fmt.Scanln(&money)
fmt.Println("请输入是否帅气(true or false)")
fmt.Scanln(&handsome)

if height > 180 && money >1.0 && handsome {
  fmt.Println("一定要嫁给他!!!")
} else if height > 180 || money >1.0 || handsome{
  fmt.Println("勉勉强强嫁给他吧")
}else {
  fmt.Println("不嫁......")
}
➜  main go run ./main.go
请输入年龄:
10
➜  main go run ./main.go
请输入年龄:
29
➜  main go run ./main.go
请输入身高(厘米)
190
请输入财富(千万)
12
请输入是否帅气(true or false)
true
一定要嫁给他!!!
➜  main go run ./main.go
请输入身高(厘米)
120
请输入财富(千万)
1
请输入是否帅气(true or false)
false
不嫁......
➜  main go run ./main.go
请输入身高(厘米)
120
请输入财富(千万)
1.2
请输入是否帅气(true or false)
false
勉勉强强嫁给他吧
➜  main 

嵌套分支

  • 基本介绍

    在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分支外面的分支结构称为外层分支。

  • 基本语法

if 条件表达式{
  if 条件表达式{
    
  }else {
    
  }
}

说明:嵌套分支不宜过多,建议控制在3层内

  • 示例代码1
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......")
}
➜  main go run ./main.go 
请输入秒数
100
out......
➜  main go run ./main.go
请输入秒数
3
请输入性别
男
进入决赛的男子组
➜  main go run ./main.go
请输入秒数
4
请输入性别
女
进入决赛的女子组
  • 示例代码2

    出票系统:根据淡旺季的月份和年龄,打印票价

    4到10是旺季:

    ​ 成人(18-60):60

    ​ 儿童(<18):半价 30

    ​ 老人(>60): 1/3 20

    淡季:

    ​ 成人:40

    ​ 其他:20

var month int
var age int
fmt.Println("请输入月份")
fmt.Scanln(&month)
if(month>=4 && month <=10){
  fmt.Println("请输入购票人年龄:")
  fmt.Scanln(&age)
  if age<18 {
    fmt.Println("您购买的票是旺季儿童票,享受半价优惠:30元")
  }else if age > 60{
    fmt.Println("您购买的票是旺季老人票,享受1/3折:20元")
  }else {
    fmt.Println("您购买的票是旺季成人票,原价购买,60元")
  }
}else {
  fmt.Println("请输入购票人年龄:")
  fmt.Scanln(&age)
  if age<18 || age>60 {
    fmt.Println("您购买的票是淡季其他票,享受半价优惠:20元")
  }else {
    fmt.Println("您购买的票是淡季成人票,原价购买,40元")
  }
}
➜  main go run ./main.go 
请输入秒数
100
➜  main go run ./main.go
# command-line-arguments
➜  main go run ./main.go
请输入月份
6
请输入购票人年龄:
19
您购买的票是旺季成人票,60元
➜  main go run ./main.go
请输入月份
2
请输入购票人年龄:
12
您购买的票是淡季其他票,20元
➜  main go run ./main.go
请输入月份
9
请输入购票人年龄:
61
您购买的票是旺季老人票,20元
➜  main go run ./main.go
请输入月份
10
请输入购票人年龄:
71
您购买的票是旺季老人票,20元
➜  main 

switch分支控制

基本介绍

  1. switch语句用于基于不同条件执行不同动作,每一个case分支都是唯一的,从上到下逐疫测试,知道匹配为止。
  2. 匹配项后面也不需要再加break

基本语法

switch 表达式 {
  case 表达式1,表达式2,...:
  	语句块1
  case 表达式3,表达式4,...:
  	语句块2
  //这里可以有多个case语句
  
  default:
  	语句块
}

switch的流程图

  • 说明和总结
    1. switch的执行的流程是,先执行表达式,得到值,然后和case的表达式进行比较,如果相等,就匹配到,然后执行对应的case的语句块,然后退出switch控制。
    2. 如果switch的表达式的值没有和任何的case的表达式匹配成功,则执行default的语句块,执行后退出switch的控制
    3. golang的case后的表达式可以有多个,使用 逗号 间隔。
    4. golang中的case语句块不需要写break,因为默认会有,即在默认情况下,当程序执行完case语句块后,就直接退出该switch控制结构。

switch快速入门案例

  • 案例:

    请编写一个程序,该程序可以接收一个字符,比如: a,b,c,d,e,f,g a表示星期一,b表示星期二 … 根据用户的输入显示相依的信息.要求使用 switch 语句完成

  • 代码

package main

import (
	"fmt"
)
func main()  {
	//分析思路
	//1. 定义一个变量接收字符
	//2. 使用switch完成
	var key byte
	fmt.Println("请输入一个字符 a,b,c,d,e,f,g")
	fmt.Scanf("%c", &key)

	switch key {
		case 'a' :
			fmt.Println("周一")
		case 'b':
			fmt.Println("周二")
		case 'c':
			fmt.Println("周三")
		case 'd':
			fmt.Println("周四")
		case 'e':
			fmt.Println("周五")
		case 'f':
			fmt.Println("周六")
		case 'g':
			fmt.Println("周日")
		default:
			fmt.Println("输入有误...")
	}
}
请输入一个字符 a,b,c,d,e,f,g
a
周一
➜  main 
➜  main go run ./main.go
请输入一个字符 a,b,c,d,e,f,g
q
输入有误...

switch的使用的注意事项

  1. case/switch后是一个表达式(即:常量值、变量、一个有返回值的函数等都可以)
//写一个很简单的函数
func test(char byte) byte {
  return char + 1
}
func main(){
  //
  var key byte
	fmt.Println("请输入一个字符 a,b,c,d,e,f,g")
	fmt.Scanf("%c", &key)
  
  switch test(key)+1 { //修改成函数了哦!!
		case 'a' :
			fmt.Println("周一")
		case 'b':
			fmt.Println("周二")
		case 'c':
			fmt.Println("周三")
		case 'd':
			fmt.Println("周四")
		case 'e':
			fmt.Println("周五")
		case 'f':
			fmt.Println("周六")
		case 'g':
			fmt.Println("周日")
		default:
			fmt.Println("输入有误...")
	}
}
  1. case后的各个表达式的值的数据类型,必须和switch的表达式数据类型一致
func main()  {
	var n1 int32 = 20
	var n2 int64 = 20
	switch n1 {
		case n2 :
			fmt.Println("ok1") //错误,因为n2和n1的数据类型不一致
		default :
			fmt.Println("没匹配到")
	}
}
  1. case 后面可以带多个表达式,使用逗号间隔。比如case 表达式1,表达式2...
func main()  {
	var n1 int32 = 20
	var n2 int32 = 20
	switch n1 {
		case n2, 10, 5 :
			fmt.Println("ok1")
		default :
			fmt.Println("没匹配到")
	}
}
  1. case后面的表达式如果是常量值(字面量),则要求不能重复
func main()  {
	var n1 int32 = 5
	var n2 int32 = 20
	switch n1 {
		case n2, 10, 5 :        //case后面可以有多个表达式
			fmt.Println("ok1") 
		case 5 :                // 错误,因为前面我们有常量5,因此重复,就会报错哦
			fmt.Println("ok2~") 
		default :
			fmt.Println("没匹配到")
		
	}
}
  1. case后面不需要带break,程序匹配到一个case后就会执行对应的代码块,然后退出switch,如果一个都匹配不到,则执行default
  2. default语句不是必须的
  3. switch后也可以不带表达式,类似 if-else分支来使用。【案例演示】
package main
import (
	"fmt"
)

func main()  {
	var age int = 10
	switch {
	case age == 10 :
		fmt.Println("age == 10")
	case age == 20 :
		fmt.Println("age == 20")
	default :
		fmt.Println("没有匹配到哦")
	}

	score := 90
	switch {
	case score > 90 :
		fmt.Println("成绩优秀..")
	case score >=70 && score <= 90:
		fmt.Println("成绩优良..")
	case score >=60 && score <= 70:
		fmt.Println("成绩及格..")
	default:
		fmt.Println("不及格!")	
	}
}
  1. 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("不及格!")
	}
  1. switch穿透-fallthrough,如果在case语句块后增加fallthrough,则会继续执行下一个case,也叫switch穿透。
//switch的穿透fallthrought
	var num int = 10
	switch num {
		case 10 :
			fmt.Println("ok1")
			fallthrough//默认只能穿透一层
		case 20:
			fmt.Println("ok2")
			fallthrough
		case 30:
			fmt.Println("ok3")
		default:
			fmt.Println("没有匹配到哦")

	}
➜  main go run ./main.go
ok1
ok2
ok3
➜  main 
  1. Type Switch : switch 语句还可以被用于 type-switch 来判断某个interface变量中实际指向的变量类型【interface体验】
var x interface{}
	var y = 10.0
	x = y
	switch i := x.(type) {
		case nil:
			fmt.Printf(" x 的类型~ : %T",i)
			fmt.Println()
		case int:
			fmt.Printf("x 是 int 型")
			fmt.Println()
		case float64:
			fmt.Printf("x 是 float64 型 ")
			fmt.Println()
		case func(int) float64:
			fmt.Printf("x 是 func(int) 型")
			fmt.Println()
		case bool, string:
			fmt.Printf("x 是 bool 或 string 型")
			fmt.Println()
		default:
			fmt.Printf("未知型")
			fmt.Println()	
	}
➜  main go run ./main.go
x 是 float64 型 

switch课堂练习

  1. 使用switch把小写类型的char型转为大写(键盘输入)。只转换a,b,c,d,e 其他的输出”other”。
func main()  {
	var ch byte
	fmt.Scanf("%c",&ch) //获取输入
	//fmt.Printf("%c",ch)
	//fmt.Println();
	switch ch {
	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")
	}
}
  1. 对学生成绩大于60分的,输出“合格”。低于60分的,输出“不合格”。(注:输入的成绩不能大于100)
func main()  {
	var score float64
	fmt.Println("请输入成绩")
	fmt.Scanln(&score)

	switch int(score / 60) {
	case 1:
		fmt.Println("及格")
	case 0:
		fmt.Println("不及格")
	default:
		fmt.Println("输入有误...")
	}
}
➜  main go run ./main.go
请输入成绩
86
及格
➜  main go run ./main.go
请输入成绩
12
不及格

switch和if的比较

总结了什么情况下使用switch,什么情况下使用if

  1. 如果判断的具体数值不多,而且符合整数、浮点数、字符、字符串这几种类型。建议使用switch语句,简洁高效。
  2. 其他情况:对区间判断和结果为bool类型的判断,使用if,if的使用范围更广。

for循环控制

基本介绍

听其名而知其意。这就是让我们的一段代码循环的执行。

一个实际的需求

  • 案例:

    编写一个程序,可以打印10句

    “你好 Golang!”。想一想怎么做?

    • 使用传统的方式实现
    func main(){
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
      fmt.Println("你好 Golang")
    }
    • for循环的快速入门
    for i := 1; i <= 10; i++ {
      fmt.Println("你好 Golang")
    }

for循环的基本语法

  • 语法格式

    for 循环变量初始化;循环条件;循环变量迭代 {
      循环操作(语句)
    }
  • 对上面的语法格式说明

    • 对for循环来说,有四个要素:
      1. 循环变量初始化
      2. 循环条件
      3. 循环操作(语句),有人也叫循环体
      4. 循环变量迭代
  • for循环执行的顺序说明:

    1. 执行循环变量初始化,比如 i:=1
    2. 执行循环条件,比如 i <= 10
    3. 如果循环条件为真,就执行循环操作:比如fmt.Println("...")
    4. 执行循环变量迭代,比如 i++
    5. 反复执行2, 3, 4步骤,直到 循环条件为False,就退出for循环。

for循环执行流程分析

  • for循环的流程图

  • 对照代码分析for循环的执行过程

for循环的使用注意事项和细节讨论

  1. 循环条件是返回一个布尔值的表达式
  2. for循环的第二种使用方式
for 循环执行条件 {
  //循环执行语句
}

将变量初始化和变量迭代写到其他位置

  • 案例演示:

  1. for循环的第三种使用方式
for {
  //循环执行语句
}

上面的写法等价 for ; ; {} 是一个无限循环,通常需要配合break语句使用

  1. Golang提供for-range的方式,可以方便遍历字符串和数组(注:数组的遍历,我们放到讲数组的时候再讲解),案例说明如何遍历字符串
  • 字符串遍历方式1-传统方式
var str string = "hello,world"
for i := 0; i < len(str); i++ {
  fmt.Printf("%c \n", str[i])//使用到下标
}
  • 字符串遍历方式2-for-range
fmt.Println()

str = "abc~ok"
for index, val := range str {
  fmt.Printf("index=%d, val=%c \n",index, val)
}
  • 上面代码的细节讨论

    如果我们的字符串含有中文,那么传统的遍历字符串方式就是错误的,会出现乱码。原因是传统的对字符串的遍历是按照字节来遍历,而一个汉字在utf8编码是对应3个字节。

    如何解决?

    ​ 需要要将 str 转成 []rune切片。

var str string = "hello,world!北京"
str2 := []rune(str) // 就是把str转成[]rune
for i :=0; i < len(str2); i++ {
  fmt.Printf("%c \n", str2[i])//使用到下标
}

​ 对应for-range遍历方式而言,是按照字符方式遍历。因此如果有字符串有中文,也是ok的

var str string = "abc~ok上海"
for index, val := range str {
  fmt.Printf("index=%d, val=%c \n", index, val)
}

golang中还有一个byte数据类型与rune相似,它们都是用来表示字符类型的变量类型。它们的不同在于:

  • byte 等同于int8,常用来处理ascii字符
  • rune 等同于int32,常用来处理unicode或utf-8字符

for循环的课堂练习

  1. 打印1-100之间所有是9的倍数的整数的个数及总和。
package main
import (
	"fmt"
)
func main()  {
	var sum int = 0
	for i := 0; i <= 100; i++ {
		if i%9==0 {
			fmt.Printf("%d ",i)
			sum += i
		}
	}
	fmt.Println()
	fmt.Printf("sum = %d \n",sum)
}
➜  main go run ./main.go
0 9 18 27 36 45 54 63 72 81 90 99 
sum = 594 
➜  main 
  1. 完成下面的表达式输出,6是可变的。

package main
import (
	"fmt"
)

func main()  {
	var n int
	fmt.Printf("请输入参数:")
	fmt.Scanln(&n)
	var m int = n
	for i := 0; i <= n; i++ {
		fmt.Printf("%d + %d = %d \n",i,m,(i+m))
		m--;
	}
}
➜  main go run ./main.go
请输入参数:6
0 + 6 = 6 
1 + 5 = 6 
2 + 4 = 6 
3 + 3 = 6 
4 + 2 = 6 
5 + 1 = 6 
6 + 0 = 6 
➜  main go run ./main.go
请输入参数:8
0 + 8 = 8 
1 + 7 = 8 
2 + 6 = 8 
3 + 5 = 8 
4 + 4 = 8 
5 + 3 = 8 
6 + 2 = 8 
7 + 1 = 8 
8 + 0 = 8 

while和do..while的实现

​ Go语言没有while和do…while语法,这一点需要注意,如果我们需要使用类似的其他语言(java/c的while和do…while),可以通过for循环来实现其使用效果。

while循环的实现

循环变量初始化
for {
  if 循环条件表达式 {
    break //跳出for循环..
  }
  循环操作(语句)
  循环变量迭代
}
  • 说明
    1. for循环是一个无限循环
    2. break语句就是跳出for循环
  • 使用上面的while实现完成输出10句“HelloWorld”
i := 10
for {
  if i==0 {
    break;
  }
  fmt.Printf("HelloWorld \n")
  i--
}

do..while的实现

循环变量初始化
for {
  循环操作(语句)
  循环变量迭代
  if 循环条件表达式 {
    break //跳出for循环..
  } 
}
  • 说明

    1. 上面的循环是先执行,再判断,因此至少执行一次。
    2. 当循环条件成立后,就会执行break,break就是跳出for循环,结束循环。
  • 案例演示

    使用do..while实现10句“HelloWorldd”

i := 10
	for {	
		fmt.Printf("HelloWorld \n")
		i--
		if i==0 {
			break;
	  }
	}

多重循环控制(重点,难点)

基本介绍

  1. 将一个循环放在另一个循环体内,就形成了嵌套循环。在外边的 for 称为外层循环在里面的 for 循环称为内层循环。【建议一般使用两层,最多不要超过3层】
  2. 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为 false 时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环。
  3. 外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n

应用案例

  1. 统计 3 个班成绩情况,每个班有 5 名同学,求出各个班的平均分和所有班级的平均分[学生的成绩从键盘输入]
func main()  {
	var classNum int = 3
	var stuNum int = 5
	var sum float64 = 0.0
	var score float64 = 0.0
	var totalsum float64 = 0.0
	for i := 1; i <= classNum; i++ {
		sum = 0.0
		for j := 1; j <= stuNum; j++ {
			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 \n", totalsum / (float64)((classNum) * stuNum))
}
  1. 统计三个班及格人数,每个班有5名同学
func main()  {
	var classNum int = 3
	var stuNum int = 5
	var sum float64 = 0.0
	var score float64 = 0.0
	var totalsum float64 = 0.0
	for i := 1; i <= classNum; i++ {
		sum = 0.0
		topNum := 0
		for j := 1; j <= stuNum; j++ {
			fmt.Printf("请输入%d班级的 第%d个学生的成绩: \n", i, j)
			fmt.Scanln(&score)
			if score >= 60 {
				topNum++
			}
			sum += score
		}
		fmt.Printf("第%d个班级的及格人数为%d, 平均分为:%v \n", i, topNum, sum / (float64)(stuNum))
		totalsum += sum
		
	}
	fmt.Printf("全体学生的平均分为: %v \n", totalsum / (float64)((classNum) * stuNum))
}
➜  main go run ./main.go
请输入1班级的 第1个学生的成绩: 
88
请输入1班级的 第2个学生的成绩: 
88
请输入1班级的 第3个学生的成绩: 
66
请输入1班级的 第4个学生的成绩: 
77
请输入1班级的 第5个学生的成绩: 
88
第1个班级的平均分为:81.4 
请输入2班级的 第1个学生的成绩: 

请输入2班级的 第2个学生的成绩: 
9
请输入2班级的 第3个学生的成绩: 
00
请输入2班级的 第4个学生的成绩: 
7
请输入2班级的 第5个学生的成绩: 
6
➜  main go run ./main.go
请输入1班级的 第1个学生的成绩: 
59
请输入1班级的 第2个学生的成绩: 
59
请输入1班级的 第3个学生的成绩: 
5
请输入1班级的 第4个学生的成绩: 
69
请输入1班级的 第5个学生的成绩: 
69
第1个班级的及格人数为2, 平均分为:52.2 
请输入2班级的 第1个学生的成绩: 
99
请输入2班级的 第2个学生的成绩: 
99
请输入2班级的 第3个学生的成绩: 
99
请输入2班级的 第4个学生的成绩: 
99
请输入2班级的 第5个学生的成绩: 
99
第2个班级的及格人数为5, 平均分为:99 
请输入3班级的 第1个学生的成绩: 
98
请输入3班级的 第2个学生的成绩: 
98
请输入3班级的 第3个学生的成绩: 
98
请输入3班级的 第4个学生的成绩: 
98
请输入3班级的 第5个学生的成绩: 
98
第3个班级的及格人数为5, 平均分为:98 
全体学生的平均分为: 83.06666666666666 
  1. 打印金字塔 【经典案例】

使用for循环完成下面的案例:请编写一个程序,可以接受一个整数,表示层数,打印出金字塔。

func main()  {
	/*
	   	  *
		 ***
		*****
	   *******
      *********
	
	
	*/
	var n int
	fmt.Printf("请输入层数:")
	fmt.Scanln(&n)
	for i := 1; i <= n; i++ {
		for j := i; j <= n; j++ {
			fmt.Printf(" ")
		}
		for k := 0; k < 2 * i - 1 ; k++ {
			fmt.Printf("*")
		}
		fmt.Println()
	}

有手就行

请输入层数:3
   *
  ***
 *****
➜  main go run ./main.go
请输入层数:5
     *
    ***
   *****
  *******
 *********
➜  main go run ./main.go
请输入层数:12
            *
           ***
          *****
         *******
        *********
       ***********
      *************
     ***************
    *****************
   *******************
  *********************
 ***********************
➜  main 
  1. 打印出九九乘法表
func main()  {
	for i := 1; i <= 9; i++ {
		for j := 1; j <= i; j++ {
			fmt.Printf("%d*%d=%d\t", j, i, i * j)
		}
		fmt.Println()
	}
}
1*1=1
1*2=2   2*2=4
1*3=3   2*3=6   3*3=9
1*4=4   2*4=8   3*4=12  4*4=16
1*5=5   2*5=10  3*5=15  4*5=20  5*5=25
1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36
1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49
1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64
1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81

跳转控制语句–break

看一个具体需求,引出break

随机生成1-100的一个数,直到生成了99这个数,看看你一共用了几次?

  • 分析:

    编写一个无限循环的控制,不停的生成随机数,当生成了99时,退出这个无限循环

//如何生成随机数
//在Go中需要生成一个随机种子,否则返回的值总是固定的。
//time.Now().Unix():返回一个从1970.1.1 00:00:00到现在的秒数
rand.Seed(time.Now().Unix())
fmt.Println("n",rand.Intn(100)+1)

break的快速入门案例

func main()  {
	var n int = 0
	var count int = 0
	rand.Seed(time.Now().Unix())
	for ;; {
		n = rand.Intn(100)+1
		if n==99{
			break
		}else {
			count++
		}
	}
	fmt.Printf("生成99共进行了 %d 次",count)
	fmt.Println()
	
	
}
  • 运行结果:
➜  main go run ./main.go
生成99共进行了 26 次
➜  main go run ./main.go
生成99共进行了 76 次
➜  main go run ./main.go
生成99共进行了 15 次
➜  main go run ./main.go
生成99共进行了 15 次
➜  main go run ./main.go
生成99共进行了 25 次

基本介绍

​ break语句用于终止某个语句块的执行,用于中断当前for循环或跳出switch语句。

基本语法

{
  ..........
  ..........
  break
  ..........
  ..........
}

以for循环使用break为例,画出示意图

break的注意事项和使用细节

  1. break语句出现在多层嵌套的语句块中时,可以通过标签指明要终止的是哪一层语句块
  2. 案例:
func main()  {
	var i int
	var j int
	var k int
	//lable2:
	for i = 0; i < 4; i++ {
		lable1:
		for j = 0; j < 10; j++ {
			for k = 0; k < 122; k++ {
				if k == 2 {
					//break // break 默认会跳出最近的for循环
					break lable1
					//break lable2
				}
			}
			
		}
	}
	fmt.Printf("i:%d j:%d k:%d \n", i, j, k)
}
  1. 对上面案例的说明:
    1. break默认会跳出最近的for循环
    2. break后面可以指定标签,跳出标签对应的for循环

课堂练习

  1. 100以内的数求和,求出 当和 第一次大于20的当前数
func main()  {
	var sum int = 0
	var i int = 0
	for i = 0; i < 100; i++ {
		sum += i
		if(sum>20){
			break
		}
	}
	fmt.Printf("i:%d \n", i)
}
➜  main go run ./main.go
i:6 
➜  main 
  1. 实现登录验证,有三次机会,如果用户名为“张无忌”,密码“888”提示登录成功,否则提示还有几次机会。
func main()  {
	var username string = "张无忌"
	var loginname string = ""
	var loginpwd string = ""
	var pwd string = "888"
	var count int = 3
	for ;; {
		if count > 0 {
			fmt.Printf("欢迎登陆,剩余的尝试登录次数错误次数:%d次 \n", count)
			fmt.Printf("请输入用户名:")
	    	fmt.Scanf("%s",&loginname)
	    	fmt.Printf("请输入密码:")
	    	fmt.Scanf("%s",&loginpwd)
		}else{
			fmt.Println("已经无法继续登陆了!")
		}
		if loginname == username && loginpwd == pwd {
			fmt.Println("登录成功!")
			break
		}else {
			count--
			fmt.Printf("密码输入错误,剩余尝试次数减一!\n")
		}
		
	}
}
➜  main go run ./main.go
欢迎登陆,剩余的尝试登录次数错误次数:3次 
请输入用户名:张三丰
请输入密码:888
密码输入错误,剩余尝试次数减一!
欢迎登陆,剩余的尝试登录次数错误次数:2次 
请输入用户名:张无忌
请输入密码:888
登录成功!

跳转控制语句-continue

基本介绍

  • continue语句用于结束本次循环,继续执行下一次循环。
  • continue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环,这个和前面的break标签的使用的规则一样。

基本语法

{
  ......
  continue
  ......
}

continue流程图

案例分析continue的使用

continue的课堂练习

  • continue实现:打印1到100之间的奇数(要求使用for循环+continue)
func main()  {
	for i := 0; i < 100; i++ {
		if i%2 == 0 {
			continue
		}else {
			fmt.Printf("%d ",i)
		}
	}
	fmt.Println()
}
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99 

跳转控制语句-goto

goto的基本介绍

  1. Go语言的goto语句可以无条件地转移到程序中指定的行。
  2. goto语句通常与条件语句配合使用。可用来实现条件转移,跳出循环体等功能。
  3. 在Go程序设计中一般不主张使用goto语句,以免造成程序流程的混乱,使理解和调试程序都产生困难

goto基本语法

goto label 
......
label:statement

goto的流程图

快速入门案例

func main()  {
	var n int = 30
	//演示goto的使用
	fmt.Println("ok1")
	if n > 20 {
		goto label1
	}
	fmt.Println("ok2")
	fmt.Println("ok3")
	label1:
	fmt.Println("ok4")
	fmt.Println("ok5")
	fmt.Println("ok6")
	fmt.Println("ok7")
}
➜  main go run ./main.go
ok1
ok4
ok5
ok6
ok7

跳转控制语句-return

介绍

return使用在方法或者函数中,表示跳出所在的方法或函数,在讲解函数的时候,会详细的介绍。

func main(){
	for i := 1; i <= 10; i++ {
		if i==3 {
			return
		}
		fmt.Println("哇哇",i)
	}
	fmt.Println("Hello World!")
}
➜  main go run ./main.go
哇哇 1
哇哇 2
  • 说明
    1. 如果return是在普通的函数,则表示跳出该函数,即不再执行函数中return后面代码,也可以理解成终止函数。
    2. 如果return是在main函数,表示终止main函数,也就是说终止程序。