流程控制

Go语言基本上继承了C/C++语言所有流程控制语句
流程控制语句主要包括:条件判断语句(if和switch)、循环控制语句(for、break和continue)和跳转语句(goto)。

流程控制

Go语言中,通过if关键字构成的条件判断语句进行条件判断,格式如下:

1
2
3
4
5
6
7
if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else {
分支3
}
  • 当表达式1的执行结果为true时,执行分支1,否则对表达式2的执行结果进行判断;

  • 若表达式2的结果为true,执行分支2;

  • 如果都不满足,则执行分支3。

  • 当表达式1的执行结果为true时,执行分支1,否则对表达式2的执行结果进行判断;

  • 若表达式2的结果为true,执行分支2;

  • 如果都不满足,则执行分支3。

注意⚠:表达式后跟的左括号必须与表达式放在同一行中,否则程序在编译时将会触发错误,导致程序编译无法通过。另外,if、else if和else分支中对应的右括号可以另外换行,也可以与对应的左括号处在同一行。

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

import "fmt"

func main() {
a := 101
if a > 100 {
fmt.Println(a,"> 100")
} else if a == 100 {
fmt.Println(a,"= 100")
} else {
fmt.Println(a,"< 100")
}
}

// 101 > 100

if还有一种较为常见的写法,就是在if的表达式前添加一个语句,使用变量接收语句返回的值,通过对该变量的判断再选择执行的分支。

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

import (
"fmt"
"runtime"
)

func main() {
if num := runtime.NumCPU();num >=1 {
fmt.Println("程序使用的CPU核心数为:",num)
}
}

// 用的CPU核心数为: 6

注意⚠: 是在if表达式前定义num变量,num变量的作用域仅限于该分支中,程序的执行结果与宿主机的配置有关。

Go语言中的循环逻辑通过for关键字实现。不同于其他编程语言,Go语言没有while关键字,不存在while循环。
for循环格式如下:

1
2
3
for 初始语句;条件表达式;赋值表达式 {
循环体
}

循环体中代码会不断地被执行,直到条件表达式的结果为false,程序才会继续执行for循环之后的程序代码。其中,初始语句、条件表达式和赋值表达式都是可选的。

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

import "fmt"

func main() {
for i:=1;i<=5;i++{
fmt.Println(i)
}
}
package main

import "fmt"

func main() {
for i:=1;i<=5;i++{
fmt.Println(i)
}
}

// 1
// 2
// 3
// 4
// 5

break语句可以用来结束for循环,而且可以在语句后面添加标签,表示退出标签对应的代码块逻辑。
注意⚠: break语句如果不带标签,则默认跳出最内层的for循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import "fmt"

func main() {
i := 1
for {
for {
if i > 5 {
fmt.Println("跳出内层for循环")
break
}
fmt.Println(i)
i ++
}
fmt.Println("跳出外层for循环")
break
}
}

// 1
// 2
// 3
// 4
// 5
// 跳出内层for循环
// 跳出外层for循环

也可以使用带标签的break语句,直接跳出最外层的for循环:

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

import "fmt"

func main() {
i := 1
OuterLoop:
for {
for {
if i > 5 {
break OuterLoop //跳出OuterLoop标签对应的循环
}
fmt.Println(i)
i++
}
}
}

// 1
// 2
// 3
// 4
// 5

continue语句可以立即结束当前循环体中的逻辑,开始下一次循环。和break语句类似,continue语句后也可跟标签,表示开始标签所对应的循环。

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

import "fmt"

func main(){
OuterLoop:
for i := 0;i < 2;i++{
for j := 0;j < 3;j++ {
if j == 1 {
fmt.Println(i,j)
continue OuterLoop
}
}
}
}

//0 1
//1 1

switch语句常用于基于大量不同条件来执行不同动作,每一个条件对应一个case分支。语句的执行过程从上至下,直到找到匹配项,匹配项后面也不需要再加break。
每一个switch语句只能包含一个可选的default分支,若没有找到匹配项,会默认执行default分支中的代码块。
Go语言中的switch语法如下:

1
2
3
4
5
6
7
8
switch var1 {
case value1:
代码块1
case value2:
代码块2
default:
代码块3
}

变量var1可以是任何类型,但value1和value2必须是相同的类型或最终结果为相同类型的表达式。每个case分支后可跟多个可能符合条件的值,使用逗号分隔它们,例如:case value1,value2,value3。

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

import "fmt"

func main() {
switch 1+1 {
case 1:
fmt.Println("1+1=1")
case 2:
fmt.Println("1+1=2")
case 3:
fmt.Println("1+1=3")
default:
fmt.Println("1+1不等于1或2或3")
}
}

//1+1=2

默认情况下,switch匹配成功后就不会执行后续其他case,如果我们需要无条件强制执行后面的 case,可以使用fallthrough关键字。

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() {
switch {
case false: //肯定不会被执行
fmt.Println("我是第一个分支 条件为false")
fallthrough
case true: //被执行
fmt.Println("我是第二个分支 条件为true")
fallthrough
case false: //因为上面有fallthrough关键字,即使是false也会被执行
fmt.Println("我是第三个分支 条件为false")
fallthrough
default: //被执行
fmt.Println("我是默认case")

}
}

上述示例中,switch语句省略了条件表达式,表达式由下面的case给出。

goto语句用于代码间的无条件跳转,格式如下:

1
goto 标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
fmt.Println("Hello")
goto sign
fmt.Println("别执行")
sign:
fmt.Println("world")
}

// Hello
// world

一般情况下,在程序中不建议使用goto语句,过多的goto语句会破坏程序结构,使程序的可读性变差。

小结

Go语言的流程控制语句主要包括:条件判断语句(if和switch)、循环控制语句(for、break和continue)和跳转语句(goto)。

  • Go语言中的循环逻辑通过for关键字实现,不存在while循环。
  • switch语句常用于基于大量不同条件来执行不同动作,每一个条件对应一个case分支。
  • 一般情况下,在程序中不建议使用goto语句,过多的goto语句会破坏程序结构,使程序的可读性变差。

循环嵌套

一个循环结构内可以含有另一个循环,这被称为循环嵌套,又称多重循环。常用的循环嵌套是二重循环,外层循环称为外循环,内层循环称为内循环。
双重循环的结构:

1
2
3
4
5
6
7
8
for (初始语句;条件表达式;赋值表达式)
{
循环体
for(初始语句;条件表达式;赋值表达式)
{
循环体
}
}

上面的结构共由两个for循环组成,它们之间的层次关系是一个嵌套住另一个,我们把这种关系叫作嵌套关系。这种层次关系是唯一且不可改变的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import "fmt"

func pyramid(n int) {
for i:=1;i<=n;i++ {
for j:=1;j<=n-i;j++{
fmt.Print(" ")
}
for k:=1;k<=2 * i-1;k++{
fmt.Print("*")
}
fmt.Println()
}
}

func main() {
x := 9
pyramid(x)
}

*
***
*****
*******
*********
***********
*************
***************
*****************

斐波那契数列

斐波那契数列,又称黄金分割数列,因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为兔子数列,指的是这样一个数列:1、1、2、3、5、8、13、21、34……这个数列从第三项开始,每一项都等于前两项之和。斐波那契数列在现代物理、准晶体结构、化学等领域都有直接的应用。
那么,我们是否可以编写一个斐波那契数列的程序,输入第n项,程序输出对应第n项的值?答案是肯定的,最常见的实现方式就是循环和递归。
在Go语言中,实现斐波那契数列的程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import "fmt"

func fibonacci(n int) (res int) {
a:=1
b:=1
for i:=2;i<n;i++{
c:=b
b = a+b
a=c
}
return b
}

func main() {
n:=9
fmt.Printf("斐波那契数列第%d项值为%d",n,fibonacci(n))
}

// 斐波那契数列第9项值为34

//a b 分别为1,求出了 1 1

//c 临时存 b = 1
//b = a+b = 2,求出了 1 1 2
//a = c 此时a = 1,一次循环结束

//c 临时存 b = 2
//b = a+b = 3,求出了 1 1 2 3
//a = c 此时a = 2,一次循环结束

//c 临时存 b = 3
//b = a+b = 5,求出了 1 1 2 3 5
//a = c 此时a = 3,一次循环结束

对于斐波那契数列,我们也可以使用递归来实现:

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

import "fmt"

func fibonacci(n int) (res int) {
if n==1 || n==2{
return 1
}else{
return fibonacci(n-2)+fibonacci(n-1)
}
}

func main(){
n:=6 //求斐波那契数列第5项的值
fmt.Printf("斐波那契数列第%d项值为%d",n,fibonacci(n))
}

// 斐波那契数列第6项值为8%

运算过程:
upload successful

在使用递归方法来实现斐波那契数列时,我们也可以用switch分支来进行代替:

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

import "fmt"

func f(n int) (rec int) {
switch n {
case 1:
return 1
case 2:
return 1
default:
return f(n-2) + f(n-1)
}

}

func main() {
n := 6
fmt.Println(f(n))
}

// 8