if…else分支结构

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

1
2
3
4
5
6
7
if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else{
分支3
}

特殊写法

if在go语言中常用的一种特殊的写法,在if表达式中添加一个可执行语句,根据语句执行的结果进行判断。

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

Connect()是一个带有返回值的函数,err := Connect()是一个语句,执行Connect()之后将错误信息保存到err变量中,err != nil 才是if的判断表达式。
这种写法可以将返回值与判断放在一行进行处理,而且返回值的作用范围被限制在 if、else 语句组合中。

for循环结构

基于语句和表达式的基本for循环格式如下:

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

初始语句

初始语句是在第一次循环前执行的语句,一般使用初始语句执行变量初始化,如果变量在此处被声明,其作用域将被局限在这个 for 的范畴内。
初始语句可以被省略,但是初始语句后面的分号不能被省略。

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

条件表达式

条件表达式是控制循环的开关,每次循环之前需要先计算条件表达式,如果条件表达式为true,则继续循环,否则将结束循环,条件表达式可以被省略,此时循环为无限循环。

  • 保留结束语句的无限循环

    1
    2
    3
    4
    5
    6
    var i int
    for ; ; i++ {
    if i > 10 {
    break
    }
    }
  • 无限循环

    1
    2
    3
    4
    5
    6
    7
    var i int
    for {
    if i > 10 {
    break
    }
    i++
    }
  • 只有一个循环条件的无限循环

    1
    2
    3
    4
    var i int
    for i <= 10 {
    i++
    }

结束语句

在结束循环前执行的语句,for 循环可以通过 break、goto、return、panic 语句强制退出循环。

打印9*9乘法表

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {
for row := 1; row <= 9; row++ {
for col := 1; col <= row; col++ {
fmt.Printf("%d*%d=%d", x, y, x*y)
}
fmt.Println()
}
}

for…range键值循环

go语言中使用for…range遍历数组、切片、字符串、map以及channel,for…range循环返回的值是有一定的规则的。

  • 数组、切片、字符串返回索引和值
  • map返回键和值
  • channel只返回通道里面的值

switch…case

C/C++ 语言中的 switch 语句只能支持数值常量,不能对字符串、表达式等复杂情况进行处理,这么设计的主要原因是性能。C/C++ 的 switch 可以根据 case 的值作为偏移量直接跳转代码,在性能敏感代码处,这样做显然是有好处的。

基本写法

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

1
2
3
4
5
6
7
8
9
var a = "hello"
switch a {
case "hello":
fmt.Println(1)
case "world":
fmt.Println(2)
default:
fmt.Println(0)
}

一个分支多个值

go语言支持一个case可以拥有多个值,值之间用逗号隔开。

1
2
3
4
5
a := "mum"
switch a {
case "mum", "daddy":
fmt.Println("family")
}

分支表达式

case后面不仅可以是常量,也可以是表达式:

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

兼容C语言的case设计

在go语言中case是一个独立的代码块,执行完毕之后不会像C语言一样紧接着下一个case的执行(黑人问号?,那为什么要搞这么残疾的东西?简直无法理解),为了兼容一些移植代码,加入了fallthrough关键字来实现这一个功能。

1
2
3
4
5
6
7
8
var s string = "hello"
switch {
case s == "hello":
fmt.Println("hello")
fallthrough
case s != "world":
fmt.Println("world")
}

既然go语言非要将case作为独立的模块,那么在编写go代码的时候就不建议使用fallthrough。

goto跳转

goto语句通过标签实现代码间的无条件跳转,goto语句可以快速的跳出循环。

使用goto退出多层循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import "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")
}

统一错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    err := firstCheckError()
if err != nil {
goto onExit
}

err = secondCheckError()
if err != nil {
goto onExit
}

fmt.Println("done")
return

onExit:
fmt.Println(err)
exitProcess()

break

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main 

import "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 outerLoop
case 3:
fmt.Println(i, j)
break outerLoop
}
}
}
}

continue

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "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
}
}
}
}