300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Go开发 之 流程控制(if/else for/range switch goto break continue)

Go开发 之 流程控制(if/else for/range switch goto break continue)

时间:2021-01-10 10:11:22

相关推荐

Go开发 之 流程控制(if/else for/range switch goto break continue)

文章目录

0、唠唠叨叨1、分支结构(if / else)1.1、标准写法1.2、特殊写法 2、循环结构(for)2.1、标准循环2.2、无限循环2.3、for 中的初始语句(开始循环时执行的语句)2.4、for 中的结束语句(循环结束时执行的语句)2.5、for 中的条件表达式(控制是否循环的开关)2.5.1、结束循环时带可执行语句的无限循环2.5.2、无限循环2.5.3、只有一个循环条件的循环 3、键值循环结构(for range)3.1、标准循环3.2、遍历数组、切片(获得索引和值)3.3、遍历字符串(获得字符)3.4、遍历 map(获得 map 的键和值)3.5、遍历通道 channel(接收通道数据)3.6、在遍历中选择希望获得的变量 4、分支结构(switch / case)4.1、基本写法4.2、一分支多值4.3、分支表达式4.4、跨越 case 的 fallthrough(兼容C语言的 case 设计) 5、跳转结构(break / continue / goto)5.1、跳出制定循环 break5.2、继续下一次循环 continue5.3、跳转到指定的标签 goto5.3.1、使用 goto 退出多层循环5.3.2、使用 goto 集中处理错误 6、示例6.1、九九乘法表6.2、冒泡排序6.3、二分查找6.4、简易聊天机器人

0、唠唠叨叨

流程控制可以说是一门语言的经脉了。Go 语言的常用流程控制有 if 和 for,而 switch 和 goto 主要是为了简化代码、降低重复代码而生的结构,属于扩展类的流程控制。

本章主要介绍 Go 语言中的基本流程控制语句,包括分支语句(if 和 switch)、循环(for)和跳转(goto)语句。另外,还有循环控制语句(break 和 continue),break 的功能是中断循环或者跳出 switch 判断,continue 的功能是继续 for 的下一个循环。

1、分支结构(if / else)

1.1、标准写法

标准格式:

if condition1 {// do something} else if condition2 {// do something else}else {// catch-all or default}

无效格式:

if x{}else {// 无效的}

1.2、特殊写法

将返回值与判断放在一行进行处理,而且返回值的作用范围被限制在 if、else 语句组合中。

if 还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断,例如:

if err := Connect(); err != nil {fmt.Println(err)return}

Connect 是一个带有返回值的函数,err:=Connect() 是一个语句,执行 Connect 后,将错误保存到 err 变量中。err != nil 才是 if 的判断表达式,当 err 不为空时,打印错误并返回。

在编程中,变量的作用范围越小,所造成的问题可能性越小,每一个变量代表一个状态,有状态的地方,状态就会被修改,函数的局部变量只会影响一个函数的执行,但全局变量可能会影响所有代码的执行状态,因此限制变量的作用范围对代码的稳定性有很大的帮助。

2、循环结构(for)

Go语言中的循环语句只支持 for 关键字,而不支持while 和 do-while 结构。

2.1、标准循环

sum := 0for i := 0; i < 10; i++ {sum += i}

2.2、无限循环

sum := 0for {sum++if sum > 100 {break}}

2.3、for 中的初始语句(开始循环时执行的语句)

初始语句是在第一次循环前执行的语句,一般使用初始语句执行变量初始化,如果变量在此处被声明,其作用域将被局限在这个 for 的范围内。初始语句可以被忽略,但是初始语句之后的分号必须要写,例如:

step := 2for ; step > 0; step-- {fmt.Println(step)}

这段代码将 step 放在 for 的前面进行初始化,for 中没有初始语句,此时 step 的作用域就比在初始语句中声明 step 要大。

2.4、for 中的结束语句(循环结束时执行的语句)

在结束每次循环前执行的语句,如果循环被 break、goto、return、panic 等语句强制退出,结束语句不会被执行。

2.5、for 中的条件表达式(控制是否循环的开关)

2.5.1、结束循环时带可执行语句的无限循环

下面代码忽略条件表达式,但是保留结束语句,例如:

var i intfor ; ; i++ {if i > 10 {break}}

2.5.2、无限循环

上面的代码还可以改写为更美观的写法。

var i intfor {if i > 10 {break}i++}

无限循环在收发处理中较为常见,但需要无限循环有可控的退出方式来结束循环。

2.5.3、只有一个循环条件的循环

满足条件表达式时持续循环,否则结束循环。

var i intfor i <= 10 {i++}

上述代码其实类似于其他编程语言中的 while,在 while 后添加一个条件表达式。

3、键值循环结构(for range)

3.1、标准循环

在许多情况下都非常有用,for range 可以遍历数组、切片、字符串、map 及通道(channel),for range 语法上类似于其它语言中的 foreach 语句,一般形式为:

for key, val := range coll {// for pos, char := range str {...}

一个字符串是 Unicode 编码的字符(或称之为 rune )集合,因此也可以用它来迭代字符串。每个 rune 字符和索引在 for range 循环中是一一对应的,它能够自动根据 UTF-8 规则识别 Unicode 编码的字符。

通过 for range 遍历的返回值有一定的规律:

数组、切片、字符串返回索引和值。map 返回键和值。通道(channel)只返回通道内的值。

3.2、遍历数组、切片(获得索引和值)

在遍历代码中,key 和 value 分别代表切片的下标及下标对应的值,数组也是类似的遍历方法:

for key, value := range []int{1, 2, 3, 4} {fmt.Printf("key:%d value:%d\n", key, value)}

代码输出如下:

key:0 value:1key:1 value:2key:2 value:3key:3 value:4

3.3、遍历字符串(获得字符)

var str = "hello 你好"for key, value := range str {fmt.Printf("key:%d value:0x%x\n", key, value)}

代码输出如下:

key:0 value:0x68key:1 value:0x65key:2 value:0x6ckey:3 value:0x6ckey:4 value:0x6fkey:5 value:0x20key:6 value:0x4f60key:9 value:0x597d

代码中的变量 value,实际类型是 rune 类型,以十六进制打印出来就是字符的编码。

3.4、遍历 map(获得 map 的键和值)

m := map[string]int{"hello": 100,"world": 200,}for key, value := range m {fmt.Println(key, value)}

代码输出如下:

hello 100world 200

对 map 遍历时,遍历输出的键值是无序的,如果需要有序的键值对输出,需要对结果进行排序。

3.5、遍历通道 channel(接收通道数据)

c := make(chan int)go func() {c <- 1c <- 2c <- 3close(c)}()for v := range c {fmt.Println(v)}

结果:

3.6、在遍历中选择希望获得的变量

m := map[string]int{"hello": 100,"world": 200,}for _, value := range m {// "_"可以理解为一种占位符,匿名变量本身不会进行空间分配,也不会占用一个变量的名字fmt.Println(value)}

代码输出如下:

100200

再看一个匿名变量的例子:

for key, _ := range []int{1, 2, 3, 4} {fmt.Printf("key:%d \n", key)}

代码输出如下:

key:0key:1key:2key:3

4、分支结构(switch / case)

Go语言的 switch 表达式不需要为常量,甚至不需要为整数,case 按照从上到下的顺序进行求值,直到找到匹配的项,如果 switch 没有表达式,则对 true进行匹配,因此,可以将 if else-if else 改写成一个 switch。

4.1、基本写法

Go语言改进了 switch 的语法设计,case 与 case 之间是独立的代码块,不需要通过 break 语句跳出当前 case 代码块以避免执行到下一行。每个 switch 只能有一个 default 分支。例如:

var a = "hello"switch a {case "hello":fmt.Println(1)case "world":fmt.Println(2)default:fmt.Println(0)}

4.2、一分支多值

不同的 case 表达式使用逗号分隔。

var a = "mum"switch a {case "mum", "daddy":fmt.Println("family")}

4.3、分支表达式

var r int = 11switch {case r > 10 && r < 20:fmt.Println(r)}

4.4、跨越 case 的 fallthrough(兼容C语言的 case 设计)

var s = "hello"switch {case s == "hello":fmt.Println("hello")fallthroughcase s != "world":fmt.Println("world")}

结果:

helloworld

新编写的代码,不建议使用 fallthrough。

5、跳转结构(break / continue / goto)

5.1、跳出制定循环 break

package mainimport "fmt"func main() {OuterLoop:for i := 0; i < 2; i++ {for j := 0; j < 5; j++ {switch j {case 2:fmt.Println(i, j)break OuterLoopcase 3:fmt.Println(i, j)break OuterLoop}}}}

结果:

0 2

5.2、继续下一次循环 continue

package mainimport "fmt"func main() {OuterLoop:for i := 0; i < 2; i++ {for j := 0; j < 5; j++ {switch j {case 2:fmt.Println(i, j)continue OuterLoop}}}}

结果:

0 21 2

5.3、跳转到指定的标签 goto

goto 语句通过标签进行代码间的无条件跳转,同时 goto 语句在快速跳出循环、避免重复退出上也有一定的帮助,使用 goto 语句能简化一些代码的实现过程。

5.3.1、使用 goto 退出多层循环

原始代码:

package mainimport "fmt"func main() {var breakAgain bool// 外循环for x := 0; x < 10; x++ {// 内循环for y := 0; y < 10; y++ {// 满足某个条件时, 退出循环if y == 2 {// 设置退出标记breakAgain = true// 退出本次循环break}}// 根据标记, 还需要退出一次循环if breakAgain {break}}fmt.Println("done")}

经过 goto 后优化:

package mainimport "fmt"func main() {for x := 0; x < 10; x++ {for y := 0; y < 10; y++ {if y == 2 {// 跳转到标签goto breakHere}}}// 手动返回, 避免执行进入标签return// 标签breakHere:fmt.Println("done")}

使用 goto 语句后,无须额外的变量就可以快速退出所有的循环。

5.3.2、使用 goto 集中处理错误

err := firstCheckError()if err != nil {fmt.Println(err)exitProcess()return}err = secondCheckError()if err != nil {fmt.Println(err)exitProcess()return}fmt.Println("done")

使用 goto 后:

err := firstCheckError()if err != nil {goto onExit}err = secondCheckError()if err != nil {goto onExit}fmt.Println("done")returnonExit:fmt.Println(err)exitProcess()

6、示例

6.1、九九乘法表

package mainimport "fmt"var Info string = "沙师弟 -- 九九乘法表"func main() {fmt.Println(Info)fmt.Println()// 遍历, 决定处理第几行for y := 1; y <= 9; y++ {// 遍历, 决定这一行有多少列for x := 1; x <= y; x++ {fmt.Printf("%d*%d=%d ", x, y, x*y)}// 手动生成回车fmt.Println()}}

结果:

6.2、冒泡排序

package mainimport "fmt"var Info string = "沙师弟 -- 冒泡排序"func main() {arr := [...]int{11,12,42,83,34,34,47,54}var n = len(arr)fmt.Println(Info)fmt.Println()fmt.Println("--------没排序前--------\n",arr)for i := 0; i <= n-1; i++ {fmt.Println("--------第",i+1,"次冒泡--------")for j := i; j <= n-1; j++ {if arr[i] > arr[j] {t := arr[i]arr[i] = arr[j]arr[j] = t}fmt.Println(arr)}}fmt.Println("--------最终结果--------\n",arr)}

结果:

沙师弟 -- 冒泡排序--------没排序前--------[11 12 42 83 34 34 47 54]--------第 1 次冒泡--------[11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54]--------第 2 次冒泡--------[11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54]--------第 3 次冒泡--------[11 12 42 83 34 34 47 54][11 12 42 83 34 34 47 54][11 12 34 83 42 34 47 54][11 12 34 83 42 34 47 54][11 12 34 83 42 34 47 54][11 12 34 83 42 34 47 54]--------第 4 次冒泡--------[11 12 34 83 42 34 47 54][11 12 34 42 83 34 47 54][11 12 34 34 83 42 47 54][11 12 34 34 83 42 47 54][11 12 34 34 83 42 47 54]--------第 5 次冒泡--------[11 12 34 34 83 42 47 54][11 12 34 34 42 83 47 54][11 12 34 34 42 83 47 54][11 12 34 34 42 83 47 54]--------第 6 次冒泡--------[11 12 34 34 42 83 47 54][11 12 34 34 42 47 83 54][11 12 34 34 42 47 83 54]--------第 7 次冒泡--------[11 12 34 34 42 47 83 54][11 12 34 34 42 47 54 83]--------第 8 次冒泡--------[11 12 34 34 42 47 54 83]--------最终结果--------[11 12 34 34 42 47 54 83]

6.3、二分查找

package mainimport "fmt"var Info string = "沙师弟 -- 二分查找法"//二分查找函数 假设有序数组的顺序是从小到大(很关键,决定左右方向)func BinaryFind(arr *[]int, leftIndex int, rightIndex int, findVal int) {if leftIndex > rightIndex {//判断 leftIndex是否大于rightIndexfmt.Println("找不到")return}middle := (leftIndex + rightIndex) / 2 //先找到 中间的下标if (*arr)[middle] > findVal {BinaryFind(arr, leftIndex, middle-1, findVal) //要查找的数,范围应该在 leftIndex 到 middle+1} else if (*arr)[middle] < findVal {BinaryFind(arr, middle+1, rightIndex, findVal) //要查找的数,范围应该在 middle+1 到 rightIndex} else {fmt.Printf("找到了,下标为:%v \n", middle)}}func main() {fmt.Println(Info)fmt.Println()//定义一个数组arr := []int{2, 3, 6, 8, 11, 22, 31, 36, 39, 54, 67, 76, 80, 81, 85, 91, 94, 98}BinaryFind(&arr, 0, len(arr) - 1, 36)fmt.Println("main arr :",arr)}

结果:

6.4、简易聊天机器人

package mainimport ("bufio""fmt""os""strings")var Info string = "沙师弟 -- 简易聊天机器人"func main() {fmt.Println(Info)fmt.Println()// 准备从标准输入读取数据。inputReader := bufio.NewReader(os.Stdin)fmt.Println("请输入你的名字:")// 读取数据直到碰到 \n 为止。input, err := inputReader.ReadString('\n')if err != nil {fmt.Printf("异常退出: %s\n", err)// 异常退出。os.Exit(1)} else {// 用切片操作删除最后的 \n 。name := input[:len(input)-1]fmt.Printf("你好, %s! 我能为你做什么?\n", name)}for {input, err = inputReader.ReadString('\n')if err != nil {fmt.Printf("异常退出: %s\n", err)continue}input = input[:len(input)-1]// 全部转换为小写。input = strings.ToLower(input)switch input {case "":continuecase "拜拜", "bye":fmt.Println("下次再回!")// 正常退出。os.Exit(0)default:fmt.Println("对不起,我不清楚你说什么……")}}}

结果:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。