Go语言的控制语句基础

概述

控制语句很好理解,即循环、条件等控制代码执行流程的语句,这些语句在Go中的形式与其他语言的差别也很小

循环语句

Go只有for循环一种循环语句

一个基本的for语句由三部分组成,每部分用分号隔开

  1. 初始化:在第一次迭代前执行
  2. 条件表达式: 在每次迭代前进行判断,一旦布尔值为false,循环就会终止
  3. 后置语句:在每次迭代的结尾执行

初始化语句通常为一个短变量声明,该声明仅在for语句的作用域中可见

示例1:for.go

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

import "fmt"

func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}

与其他语言像C、Java等语言不同的是,Go的for语句后面三个部分外没有(),但{}是必需的

示例1编译运行后可以看到程序输出结果

1
45

for循环的三个部分中初始化语句和后置语句是可选项,例如

1
2
3
4
5
6
sum := 1
for ; sum < 1000; {
sum += sum
}
// 这个for循环只有一个条件表达式
// 初始化语句和后置语句都被省略了

编译运行后输出结果1024,可以看出每次循环都执行sum += sum直到sum的值大于等于1000

在这种情况下把语句中的分号去掉,很容易看出来这就是其他语言中的while循环

1
2
3
4
5
sum := 1
for sum < 1000 {
sum += sum
}
// 在Go中for即是while

至此我们已经省略了for循环三部分中的两部分,如果将剩下的一个部分————条件表达式也省略,这是这个循环就成了无限循环

1
2
3
for {

} // 这是个无限循环

条件语句

条件语句包括if、switch等对条件进行判断的语句

if语句

与for类似,if语句无需()而{}是必须的,基本形式的的if语句只有一个部分————条件表达式

示例2:if.go

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"
"math"
)
// 导入fmt和math包

func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
// 判断x < 0
// true 返回-x的计算结果,并在结尾加上表示复数虚部的符号i
// false 返回x的计算结果

func main() {
fmt.Println(sqrt(2),sqrt(-4))
}
// 输出2和-4的平方根

编译运行后输出结果

1
1.4142135623730951 2i

if语句允许在条件表达式前执行一个简单的语句,该语句声明的变量作用域仅在if之内

示例3:if-with-a-short-statement.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
package main

import (
"fmt"
"math"
)

func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
}
return lim
}
// 在条件判断前先声明一个变量v,v的值为x的n次方
// 判断v < lim
// true 返回v
// false 返回lim

func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}

编译运行后输出结果

1
9 20

在if语句后可以选择使用else语句,if语句中的声明在else语句中同样可以使用

对示例3中pow函数稍作修改

1
2
3
4
5
6
7
8
9
10
11
12
13
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
// 这里开始就不能使用 v 了
return lim
}
// 在条件判断前先声明一个变量v,v的值为x的n次方
// 判断v < lim
// true 返回v
// false 返回字符串“ v >= lim ”和lim

编译运行

1
2
27 >= 20
9 20

注意

实际在main的fmt.Println调用之前对pow函数调用就已经执行完成并返回各自的结果

一个小小的练习

练习1:用牛顿法实现平方根函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 迭代10次,计算x的平方根,并打印每次的z值
package main

import (
"fmt"
)

func Sqrt(x float64) float64 {
z := float64(1)
for i:=0 ; i < 10 ; i++ {
z -= (z*z - x) / (2*z)
fmt.Println(i,": ",z,"\n")
}
return z
}

func main() {
fmt.Println(Sqrt(2))
}

编译运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0 :  1.5 

1 : 1.4166666666666667

2 : 1.4142156862745099

3 : 1.4142135623746899

4 : 1.4142135623730951

5 : 1.414213562373095

6 : 1.4142135623730951

7 : 1.414213562373095

8 : 1.4142135623730951

9 : 1.414213562373095

1.414213562373095

换一种实现方法,当z的值停止改变时退出循环

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 Sqrt(x float64) float64 {
z := float64(1)
i := 0.0
for j := 0; j >= 0; j++ {
if i != z {
i = z
z -= (z*z - x) / (2*z)
} else {
return z
}
fmt.Println(j,":",z,"\n")
}
return z
}

func main() {
fmt.Println(Sqrt(2))
}

什么是牛顿法:

z² − x 是 z² 到它所要到达的值(即 x)的距离, 除以的 2z 为 z² 的导数,我们通过 z² 的变化速度来改变 z 的调整量。 这种通用方法叫做牛顿法。 它对很多函数,特别是平方根而言非常有效。

switch语句

switch是编写一连串if-else语句的简便写法,它运行第一个值等于条件表达式的case语句,语法结构如下:

1
2
3
4
5
6
7
8
switch var {
case val1 :
...
case val2 :
...
default :
...
}

其中var可以是任何类型,val1和val2则是同类型的任意值。

case语句从上到下顺序执行,直到匹配成功。默认情况下Go不会运行之后所有的case语句,即自带break语句。如果需要执行后面的case语句,则需要以fallthrough语句结束。

示例4:switch.go

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

import (
"fmt"
"runtime"
)

func main() {
fmt.Print("Go runs on ")
//判断Go当前所运行在的系统并返回
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.\n", os)
}
}

编译运行

1
Go runs on windows

switch语句允许没有条件表达式,其等价于switch true,这种形式在面对一长串的if-then-else情况下可以写出更清晰的代码

defer语句

defer语句的功能是延迟执行,defer语句会将函数推迟到外层函数返回后再执行,推迟调用的函数其参数会立即求值,但是直到外层函数返回前该函数都不会被调用。

示例5:defer.go

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
defer fmt.Println("world")

fmt.Println("hello")
}

编译运行

1
2
hello
world

多个defer语句的调用遵循后进先出,即推迟执行的函数会被压入一个栈中

示例6:defer-more.go

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

import "fmt"

func main() {
fmt.Println("counting")

for i := 0;i < 10; i++ {
defer fmt.Println(i)
}

fmt.Println("done")
} // 降序输出0-9

编译运行

1
2
3
4
5
6
7
8
9
10
11
12
counting
done
9
8
7
6
5
4
3
2
1
0
作者

Luc_41

发布于

2020-03-17

更新于

2020-03-23

许可协议

评论