Golang开发之流程控制
1. 条件判断(if)
Go语言if条件判断格式如下:
if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else {
分支3
}
Go 规定与 if 匹配的左括号 “{” 必须与 if 和表达式放在同一行,如果尝试将“{”放在其它位置,将会触发编译错误,同理else也是。
举例:
var ten int = 11
if ten > 10 {
fmt.Println(">10")
} else {
fmt.Println("<=10")
}
特殊写法:
可以在if表达式之前添加一个执行语句,再根据变量值进行判断:
if err := Connect(); err != nil {
fmt.Println(err)
return
}
err != nil 才是 if 的判断表达式,当 err 不为空时,打印错误并返回。
2. 构建循环(for)
for 循环格式如下:
for 初始语句;条件表达式;结束语句{
循环体代码
}
结束语句为最后执行。
2.1. for 中的初始语句一一开始循环时执行的语句
初始语句是在第一次循环前执行的语句,其作用域将被局限在这个for的范畴内。
初始语句可以被忽略,但是初始语句之后的分号必须要写:
step := 2
for ; step > 0; step-- {
fmt.Println(step)
}
这段代码for中没有初始语句,此时step的作用域就比在初始语句声明step要大。
2.2. for 中的条件表达式-一控制是否循环的开关
2.2.1. 结束循环时带可执行语句的无限循环
var i int
for ; ; i++ {
if i > 10 {
break
}
}
2.2.2. 无限循环
var i int
for {
if i > 10 {
break
}
i++
}
2.2.3. 只有一个循环条件的循环
var i int
for i <= 10{
i++
}
3. 示例:九九乘法口诀表
for y := 1; y <= 9; y++ {
for x := 1; x <= y; x++ {
fmt.Printf("%d * %d = %d ", x, y, x*y)
}
fmt.Println()
}
4. 键值循环( for range )一一直接获得
Go 语言可以使用 for range 遍历数组、切片、 字符串 map 及通道( channel )。通过 for range 遍历的返回值有一定的规律:
- 数组、切片、字符串返回索引和值。
- map返回键和值。
- 通道(channel)只返回通道内的值。
4.1. 遍历数组、切片一一获得索引和元素
在遍历代码中, key value 分别代表切片的下标、下标对应的值。
func main() {
for key, value := range []int{1,2,3,4} {
fmt.Printf("key:%d value:%d
", key, value)
}
}
//代码输出如下:
//key : 0 value:1
//key : 1 value:2
//key : 2 value:3
//key : 3 value:4
4.2. 遍历字符串一一获得字符
key value 分别代表字符串的索引 (base0)和字符串中的每一个字符。
func main() {
var str = "hello 你好"
for key, value := range str {
fmt.Printf("key:%d valye:0x%x
", key, value)
}
}
//key : 0 value : Ox68
//key : 1 value : Ox65
//key : 2 value : Ox6c
//key : 3 value : Ox6c
//key : 4 value : Ox6f
//key : 5 value : Ox20
//key : 6 value : Ox4f60
//key : 9 value : Ox597d
代码中的v变量,实际类型是rune,实际上就是 int32 ,以十六进制打印出来就是字符的编码。
4.3. 遍历 map一一一获得 map 的键和值
对于 map 类型来说,for range 遍历时, key value 分别代 map 的索引键 key 和索引对应的值。
func main() {
m := map[string]int{
"hello":100,
"world":200,
}
for key, value := range m {
fmt.Println(key, value)
}
}
//代码输出如下
//hello 100
//world 200
注意: 遍历时,遍历输出的键值是无序的,如果需要有序的键值对输出,需要对结果进行排序
4.4. 遍历通道 channel 一一接收通道数据
for range 可以遍历通道(channel) ,但通道在遍历时,只输出一个值,即管道内的对应的数据。
func main() {
c := make(chan int)
go func (){
c <- 1
c <- 2
c <- 3
close(c)
}()
for v := range c{
fmt.Println(v)
}
}
//代码输出如下
//1
//2
//3
4.5. 在遍历中选择希望获得的变量
使用 for range 循环遍历某个对象一般不会同时需要key 或者 value
func main() {
m := map[string]int{
"world" : 100,
"hello" : 200,
}
for _, value := range m{
fmt.Println(value)
}
}
//代码输出如下
//100
//200
本身这种变量不会进行空间分配,也不会占用一个变量的名字。
在for range 可以对 key 使用匿名变量,也可以对 value 用匿名变量。
5. 分支选择( switch )一一拥青多个条件分支的判断
分支选择可以理解为一种批量的 if 语句 ,使用 switch 语句可方便地对大量的值进行判断。
5.1. 基本写法
func main() {
var a ="hello"
switch a{
case "hello":
fmt.Println(1)
case "world":
fmt.Println(2)
default:
fmt.Println(0)
}
}
// 代码输出如下:
// 1
上面例子中,每个case 均是字符串格式,且使用了 default 分支, Go规定定每个switch 只能有一个 default 分支。
5.1.1. 一分支多值
func main() {
var a = "num"
switch a {
case "mum", "daddy":
fmt.Println("family")
}
}
不同的 case 表达式使用逗号分隔。
5.1.2. 分支表达式
case 后不仅仅只是常量, 还可以和if一样添加表达式:
func main() {
var r int = 11
switch {
case r > 10 && r<20:
fmt.Println(r)
}
}
5.1.3. 跨越 case 的 fallthrough 兼容C语言的 case 设计
在 Go 语言中 case 是一个独立的代码块,执行完毕后不会像C语言那样紧接着下一个 case 执行。但是为了兼容一些移植代码,依然加入了 fallthrough 关键字来实现这一功能,代码如下:
func main() {
var s = "hello"
switch {
case s == "hello":
fmt.Println("hello")
fallthrough
case s != "world":
fmt.Println("world")
}
}
// 代码输出如下
// hello
// world
新编写的代码,不建议使用 fallthrough。
6. 跳转到指定代码标签(goto)
goto 语句通过标签进行代码间的无条件跳转。 goto 语句可以在快速跳出循环、避免重复退出。 Go 语言中使用 goto 语句能简化一些代码的实现过程。
6.1 使用goto退出多层循环
下面这段代码在满足条件时,需要连续退出两层循环,使用传统的编码方式如下:
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优化:
func main() {
// 外循环
for x := 0; x < 10; x++ {
//内循环
for y := 0; y < 10; y++ {
// 满足某个条件时,退出循环
fmt.Println(y)
if y == 2 {
// 跳转标签
goto breakHere
}
}
// 手动返回,避免执行进入标签
return
}
breakHere:
fmt.Println("done")
}
return如果不手动返回在不满足条件时,breakHere 也会执行代码
6.2 统一错误处理
多处错误处理存在代码重复时是非常棘手的 ,例如
func main() {
err := fiirstCheckError()
if err != nil {
fmt.Println(err)
exitProcess()
return
}
err = secondCheckError()
if err != nil {
fmt.Println(err)
exitProcess()
return
}
fmt.Println("done")
}
如果使用 goto 语句来实现同样的逻辑:
func main() {
err := fiirstCheckError()
if err != nil {
goto onExit
}
err = secondCheckError()
if err != nil {
goto onExit
}
fmt.Println("done")
return
onExit:
fmt.Println(err)
exitProcess()
}
7. 跳出指定循环( break )一一可以跳出多层循环
break 语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的 for、switch、select 的代码块上。
func main() {
OuterLoop:
for i := 0; i < 2; i++ {
for j := 0; j < 5; j++ {
switch j {
case 2:
fmt.Println(i, j)
break OuterLoop
case 3:
fmt.Println(i, j)
break OuterLoop
}
}
}
}
8. 继续下一次循环(continue)
continue 语句可以结束当前循环, 开始下一次的循环法代过程, 仅限在 for 循环用。在 continue 语句后添加标签时 表示开始标签对应的循环。
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
}
}
}
}