<7>Golang基础进阶——流程控制

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\n", 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\n", 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
}
}
}
}

 

posted @ 2020-04-11 17:35  Wshile  阅读(217)  评论(0编辑  收藏  举报