[Go 入门] 第四章 控制流程

Go 入门系列参考于互联网资料与 人民邮电出版社 《Go 语言入门经典》 与 《Effective Go》,编写目的在于学习交流,如有侵权,请联系删除

接下来将会介绍控制流程以及代码执行流程是如何确定的,本文内容:

使用 if 语句

if 语句是计算机程序的重要组成部分,if语句检查指定的条件,并在条件满足时执行指定的操作,如下

1
2
3
4
5
6
func main() {
b := true
if b {
fmt.Println("b is true !")
}
}

对以上代码的解读如下:

  • 声明变量b并将其初始化为true,这个变量被推断为布尔类型
  • 使用一条 if 语句判断b是否为true
  • 由于这条语句if语句的结果为true,因此执行大括号内的代码
  • 在终端打印一行文本,指出b为true

可执行运行多条的if语句,运行顺序与这些语句在源代码中出现的顺序相同
if语句总是计算一个布尔表达式,在它为true时执行大括号内的代码,在它为false的时候则不执行

使用 else 语句

else 语句执行了到达该分支时将被执行的代码。他不做任何判断,只要达到它所在的分支就执行。大致而言,else相当于,如果其他条件都不为true,就执行这条语句

else 语句可用来处理前面if语句结果不为true的情形,如下:

1
2
3
4
5
6
7
8
func main() {
b := false
if b {
fmt.Println("b is true!")
} else {
fmt.Println("b is false!")
}
}

如果if语句的结果为true,就不会执行else语句。else语句指定了前面所有语句的结果都为false时要执行的代码,只要前面有一条语句的结果为true,它就会被忽略。

使用 else if 语句

在当需要依次判断多个布尔表达式时,可以使用else if语句。else if语句能够让您在前面的布尔表达式为false时,接着判断后面的布尔表达式。

1
2
3
4
5
6
7
8
func main() {
i := 2
if i == 3 {
fmt.Println("i is 3")
} else if i == 2 {
fmt.Println("i is 2")
}
}

对以上代码的解读为:

  • 声明变量i将其初始化为2
  • 第一条if语句判断i是否为3,如果不是,就忽略下一行代码
  • else if语句使用另一个布尔表达式判断i是否为2
  • 由于i为2,因此执行下一行代码,向终端打印一行文本

elseelse if语句的根本不同在于,else if语句能够让您判断布尔条件,而else语句在到达其所在的分支时就会执行

使用比较运算符

布尔表达式只是返回truefalse,但使用比较运算符可执行更复杂的评估,以下是比较运算符

比较运算符

字符 运算符
== 等于
!= 不等
< 小于
<= 小于等于
> 大于
>= 大于等于

使用算数运算符

结合使用算数运算符和比较运算符来创建管理控制流程的布尔表达式

算术运算符

字符 运算符
+ 和(加)
- 差(减)
* 积(乘)
/ 商(除)
% 余(模)

使用逻辑运算符

除比较运算符和算数运算符外,逻辑运算符也可以用于支持流程控制。

逻辑运算符

字符 运算符
&& 与:两个条件是否都为true
|| 或:两个条件是否至少有一个为true
非:条件是否为false

使用 switch 语句

switch 语句可用来替代冗长的if else布尔比较,很多程序员喜欢用switch语句(而不使用else if语句),从编译层面上来说,这样的代码效率也可能更高。除了少量的else if比较外,其他的都可以替换为switch语句,这样不仅可提高代码的可读性,还能提高效率

1
2
3
4
5
6
7
8
9
10
11
12
func main() {
i := 2

switch i {
case 2:
fmt.Println("Two")
case 3:
fmt.Println("Three")
case 4:
fmt.Println("Four")
}
}

对上述代码的解读如下:

  • switch语句指定了一个要评估的变量 i
  • 在一系列的 case 语句中指定了要与变量 i 比较的表达式
  • 如果这个表达式的结果与 i 相等,就执行相应的语句
  • 如果这个表达式的结果与 i 不等,就跳到下一条 case 语句
  • 在这里,由于 i 为2,因此向终端打印单词 Two

相比于else if条件,switch语句更简洁,它还支持其他case条件都不满足时将执行的default case。在switch语句中,可使用default来指定其他case条件都不满足时将要执行的代码,default case通常放在switch语句末尾,但也可以放在其他地方。

1
2
3
4
5
6
7
8
9
10
11
12
func main() {
s := "c"

switch s {
case "a":
fmt.Println("The letter a!")
case "b":
fmt.Println("The letter b!")
default:
fmt.Println("I don't recognize that letter")
}
}

使用 for 语句进行循环

for 语句能够反复执行代码块,这在编程中称为循环:反复执行代码块,直到条件不再满足。如下的示例,将一个数字不断加1,直到它为特定的数字:

1
2
3
4
5
6
7
func main() {
i := 0
for i < 10 {
i++
fmt.Println("i is", i)
}
}

对以上代码的解读为:

  • 声明变量i并将其初始化为0
  • 一条 for 语句判断i是否小于10
  • 如果这个布尔条件为true,就执行for语句中的代码
  • 使用递增运算符将变量i加1
  • 将变量i的值打印到终端
  • 返回到开头的布尔表达式,判断变量i的值是否小于10
  • 变量i不再小于10时,这个布尔表达式将为false,因此不再执行for语句中的代码,循环就此结束

包含初始化语句和后续语句的 for 语句

除要检查的条件外,for语句还可指定在循环开始时执行的初始化语句以及后续(post)语句,这些语句可让迭代代码简短得多,但必须使用分号将他们分隔开

  • 初始化语句:仅在首次迭代前执行
  • 条件语句:每次迭代前都将检查的布尔表达式
  • 后续语句:每次迭代后都将执行
1
2
3
4
5
func main() {
for i := 0; i < 10; i++ {
fmt.Println("i is", i)
}
}

对以上代码的解读为:

  • 声明变量i并将其初始化为0
  • 一条for语句检查变量i是否小于10
  • 如果这个布尔表达式为true,就执行for语句中的代码
  • 使用递增运算符将变量i的值加1
  • 将变量i的值打印到终端
  • 返回到开头的布尔表达式,判断变量i的值是否小于10
  • 变量i不再小于10时,这个布尔表达式将为false,因此不再执行for语句中的代码,循环就此结束

包含 range 子句的 for 语句

for 语句也可用来遍历数据结构,在下面代码中,创建了一个数组,用于储存一系列数字。

1
2
3
4
5
6
7
func main() {
numbers := []int{1, 2, 3, 4}
for i, n := range numbers {
fmt.Println("The index of the loop is", i)
fmt.Println("The value from the slice is", n)
}
}

对于上述代码的解读为:

  • 声明变量numbers,并将一个包含4个整数的数组赋予给它
  • for 语句指定了迭代变量i,用于存储索引值,这个变量将在每次迭代结束后更新
  • for 语句指定了迭代变量i,用于储存来自数组中的值。它也将在每次迭代结束后更新
  • 在循环中,打印这两个变量的值

注意事项:

迭代变量从0开始,且每次加1。要在特定的迭代中执行操作,务必从0而不是1开始计算迭代数

关于 range

  • range 类似迭代器,可以遍历数组,字符串,map等等,对象的不同,返回的结果也不同
  • range 会复制对象,而不是不是直接在原对象上操作
  • 使用 range 迭代遍历引用类型时,底层的数据不会被复制

使用 defer 语句

defer 是一个很有用的Go语言功能,它能够让您在函数返回前执行另一个函数。函数遇到return语句或达到函数末尾时返回。defer语句通常用于执行清理操作或确保操作(如网络调用)完成后再执行另一个函数

1
2
3
4
func main() {
defer fmt.Println("I am run after the function completes")
fmt.Println("Hello world!")
}

对于上面的代码的解读为:

  • 使用一条 defer 语句,在它所在的函数执行完毕后执行另一个函数
  • 向终端打印 Hello world!,外部函数就此结束
  • 外部函数结束后,执行 defer 语句指定的函数

完成后,终端输出:

1
2
Hello world!
I am run after the function completes

注意:

多条defer语句时,按照源代码中的相反顺序执行

1
2
3
4
5
6
func main() {
defer fmt.Println("I am the first defer statement")
defer fmt.Println("I am the second defer statement")
defer fmt.Println("I am the third defer statement")
fmt.Println("Hello world!")
}

执行后输出:

1
2
3
4
Hello world!
I am the third defer statement
I am the second defer statement
I am the first defer statement

问题列表

  • 可以使用多种运算符(如比较运算符和算数运算符)来创建布尔表达式吗

    能。布尔表达式可包含任意数量的运算符

  • 该使用 else if 还是 switch 语句

    else ifswitch都是定义控制流程的合法方式。很多程序员发现,相比于使用一系列else if,使用switch语句编写的代码更容易理解,因此建议使用switch语句

  • 为何要使用defer语句,而不直接使用常规的控制流程

    一些需要使用defer语句的例子包括:

    • 在读取文件后,需要将其关闭
    • 收到来自 Web 服务器的响应后对其进行处理以及建立连接后向数据库请求数据
    • 需要在某项工作完成后执行特定函数

All articles in this blog adopt the CC BY-SA 4.0 agreement unless otherwise stated. Please indicate the source for reprinting!