Go语言之流程控制

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

条件判断(if)

在Go 语言中,可以通过if 关键字进行条件判断,格式如下:

if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else{
分支3
}

当表达式1为true时,执行分支1的语句,否则如果表达式2为true,则执行分支2,如果都不满足,那么执行分支3

Go 语言规定与if 匹配的左括号”{“必须与if 和表达式放在同一行,如果放在其他位置,那么将会出错。同理,与else 匹配的 “{” 也必须与else 在同一行, else 也必须与上一个if 或else if 的右边的大括号在一行

例如:下面定义两个变量,通过if语句进行判断,如图:

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

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

Connect 是一个带有返回值的函数, err := Connect()是一个语句,执行Connect 后,将错误保存到err变量中

err !=nil 才是if 的判断表达式,当err 不为空时,打印错误并返回。

这种写法可以将返回值与判断放在一行进行处理,而且返回值的作用范围被限制在

if、else 语句组合中

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

构建循环(for):

Go 语言中的所有循环类型均可以使用for 关键字来完成,语法格式如下:

for 初始语句; 条件表达式; 结束语句{
循环体代码
}

循环体不停地进行循环,直到条件表达式返回false 时自动退出循环,执行for 的”}”之后的语句。

for 循环可以通过break 、goto 、return、panic 语句强制退出循环。for 的初始语句、条件表达式、结束语句的详细介绍如下

1、for 中的初始语句—-开始循环时执行的语句

初始语句是在第一次循环前执行的语旬,一般使用初始语句执行变量初始化,如果变量在此处被声明,其作用域将被局限在这个for 的范畴内

初始语句可以被忽略,但是初始语句之后的分号必须要写,代码如下:

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

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

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

对每次循环开始前计算的表达式, 如果表达式为true ,则循环继续,否则结束循环。条件表达式可以被忽略,被忽略条件的表达式默认形成无限循环。

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

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

说明:

  • 无须设置i 的初始值, 因此忽略for 的初始语句。两个分号之间是条件表达式, 也被忽略,此时循环会一直持续下去: for 的结束语句为i++ ,每次结束循环前都会调用
  • 判断i 大于1 0 时,通过break 语句跳出for 循环

无限循环:

上面的代码还可以改写为更美观的写法,代码如下:

说明:

  • 忽略for 的所有语句,此时for 执行无限循环
  • 将i ++从for 的结束语句放置到函数体的末尾是等效的,这样编写的代码更具有可读性

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

只有一个循环条件的循环:

在上面代码的基础上进一步简化代码,将if 判断整合到for 中,变为下面的代码:

执行结果如下:

上面这段代码其实类似于其他编程语言中的while ,在while 后添加一个条件表达式,满足条件表达式时持续循环,否则结束循环。

键值循环(for range)

Go 语言可以使用for range 遍历数组、切片、字符串、map 及通道( channel )通过for range 遍历的返回值有一定的规律:

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

1、遍历数组、切片—-获得索引和元素

2、遍历字符串—–获得字符

3、遍历map—-获取map的键和值

对于map 类型来说, for range 遍历时, key 和value 分别代表map 的索引键key 和索引对应的值, 一般被称为map 的键值对。

下面的例子表示遍历map,如图:

注意:上方每个元素后面都有逗号,对于map的遍历,值是无序的,如果要指定顺序,需要对结果进行排序

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

for range 可以遍历通道( channel ) ,但是通道在遍历时,只输出一个值,即管道内的类型对应的数据,如下:

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

在使用for range 循环遍历某个对象时, 一般不会同时需要key 或者value , 这个时候可以采用一些技巧,让代码变得更简单。下面将前面的例子修改一下,如图:

上图中的例子是将键设置为匿名变量,也可以将值用匿名变量替代

总结一下for 的功能:

  • Go 语言的for 包含初始化语句、条件表达式、结束语旬, 这3 个部分均可缺省。
  • for range 支持对数组、切片、字符串、map 、通道进行遍历操作。
  • 在需要时,可以使用匿名变量对for range 的变量进行选取。

6、在golang1.22开始,for…range支持遍历整数,如图:

注:range 6的值是从0开始,但是不包括6,go1.22以前版本会报错cannot range over a (variable of type int)

分支选择(switch)—拥有多个条件分支的判断

在Go 语言中的switch ,不仅可以基于常量进行判断,还可以基于表达式进行判断。

Go 语言的switch 中的每一个case 与case 间是独立的代码块,不需要通过break 语句跳出当前case 代码块以避免执行到下一行,如下例子:

上面例子中,每一个case 均是字符串格式,且使用了default 分支, Go 语言规定每个switch 只能有一个default 分支

1、一分支多值:

当出现多个case 要放在一起的时候,可以像下面代码这样写:

最终的打印结果为匹配,说明上述的case只要匹配一个就算成功,相当于”或” 条件,注意:不同的case 表达式使用逗号分隔

2、分支表达式

case 后不仅仅只是常量,还可以和if 一样添加表达式,代码如下:

上述代码中的&&表示与条件,也可以根据需要设置或(||)条件

注意,这种情况的switch 后面不再跟判断变量, 连判断的目标都没有了

3、跨越case 的fallthrough

在Go 语言中case 是一个独立的代码块,执行完毕后不会像C 语言那样紧接着下一个case 执行。但是为了兼容一些移植代码,依然加入了fallthrough 关键字来实现这一功能,代码如下:

结果如下:

switch 语句可用来替代冗长的if else 布尔比较,从编译层面上说,switch代码效率更高。除少量的 if else 外,其他的都可替换为 switch 语句,不仅可提高代码的可读性,还可提高其性能。

跳转到指定代码标签(goto)

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

1、使用goto 退出多层循环

下面这段代码在满足条件时,需要连续退出两层循环,使用传统的编码方式如下:

2、使用goto 集中处理错误:

将上面的代码使用Go 语言的goto 语句进行优化,标签可自定义设置,如下:

上图中当满足条件y==2的时候,将会跳出循环,跳到标签gongguan位置,执行标签后面的内容,如图:

注意上面的return,如果不写return,那么当条件满足的时候,也会执行标签gongguan最下面的fmt.Println(“当y=2的时候,跳出所有循环”),当条件不满足的时候,也会执行 fmt.Println(“当y=2的时候,跳出所有循环”) ,因此,如果我们要想实现满足条件才执行标签下方的内容,不满足不执行,那么就要加上return,如下图,将return注释,当条件不满足的时候,可以发现标签下的内容还是会执行,如图:

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

3、统一错误处理:

多处错误处理存在代码重复时是非常棘手的,例如:

上面的代码中,错误处理代码是重复,此时可以通过goto来处理,如图:

跳出指定循环(break)—可以跳出多层循环

break 语句可以结束for 、switch 和select 的代码块。break 语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的for 、switch 和select的代码块上

继续下一次循环(continue)

continue 语句可以结束当前循环, 开始下一次的循环迭代过程, 仅限在for 循环内使用。在continue 语句后添加标签时, 表示开始标签对应的循环。例如:

使用延迟执行语句(defer)

defer语句能够在函数返回前执行另一个函数,函数在遇到return语句或者到达函数末尾时返回,defer语句通常用于执行清理操作或者确保操作(如网路调用),完成后执行另一个函数,下面的例子定义了三条defer和一条正常的函数语句,如图:

代码执行结果如下:

从结果中可以看出,当函数内部正常执行完成后,开始执行defer语句,并且按照defer定义的顺序相反的顺序执行语句,因此是第三个defer语句先执行

标签