所谓流程控制就是指“程序怎么执行”或者说“程序执行的顺序”。程序整体上确实是从上往下执行,但又不单纯是从上往下。 流程控制可分为三类:
- 顺序执行。这个非常简单,就是先执行第一行再执行第二行……这样依次从上往下执行。
- 选择执行。有些代码可以跳过不执行,有选择地执行某些代码。
- 循环执行。有些代码会反复执行。
11.1 条件语句
在 Go 中 条件语句模型 如下:
if 条件1 {
逻辑代码1
} else if 条件2 {
逻辑代码2
} else if 条件 ... {
逻辑代码 ...
} else {
逻辑代码 else
}
如果分支的 condition 为真,则执行该分支 { 和 } 之间的代码。在 Go 中,对于 { 和 } 的位置有严格的要求,它要求 else if (或 else ) 和两边的花括号,必须在同一行。特别注意,即使在 { 和 } 之间只有一条语句,这两个花括号也是不能省略的。
-
单分支判断
只有一个
if为单分支判断:score := 88 if score >= 60 { fmt.Println("成绩及格") } -
双分支判断
有
if和一个else为两分支判断:score := 88 if score >= 60 { fmt.Println("成绩及格") } else { fmt.Println("成绩不及格") } -
多分支判断
有
if、else if以及else为多分支判断:score := 88 if score >= 90 { fmt.Println("成绩等级为A") } else if score >= 80 { fmt.Println("成绩等级为B") } else if score >= 70 { fmt.Println("成绩等级为C") } else if score >= 60 { fmt.Println("成绩等级为D") } else { fmt.Println("成绩等级为E 成绩不及格") } -
条件语句高级写法
if还有另外一种写法,它包含一个statement可选语句部分,该可选语句在条件判断之前运行。它的语法是:if statement; condition { }上面单分支判断的那个例子可以重写如下:
if score := 88; score >= 60 { fmt.Println("成绩及格") }
11.2 选择语句
在 Go 选择语句模型 如下:
switch 表达式 {
case 表达式值1:
业务逻辑代码1
case 表达式值2:
业务逻辑代码2
case 表达式值3:
业务逻辑代码3
case 表达式值 ...:
业务逻辑代码 ...
default:
业务逻辑代码
}
switch 语句是一个选择语句,用于将 switch 后的表达式的值与可能匹配的选项 case 后的表达式进行比较,并根据匹配情况执行相应的代码块,执行完匹配的代码块后,直接退出 switch-case 。如果没有任何一个匹配,就会执行 default 的代码块。它可以被认为是替代多个 if-else 子句的常用方式。注意:case 不允许出现重复项。例如,下面的例子会输出 Your score is between 80 and 90. 。
grade := "B"
switch grade {
case "A":
fmt.Println("Your score is between 90 and 100.")
case "B":
fmt.Println("Your score is between 80 and 90.")
case "C":
fmt.Println("Your score is between 70 and 80.")
case "D":
fmt.Println("Your score is between 60 and 70.")
default:
fmt.Println("Your score is below 60.")
}
-
一个 case 多个条件
在 Go 中,
case后可以接多个条件,多个条件之间是 或 的关系,用逗号,相隔。month := 5 switch month { case 1, 3, 5, 7, 8, 10, 12: fmt.Println("该月份有 31 天") case 4, 6, 9, 11: fmt.Println("该月份有 30 天") case 2: fmt.Println("该月份闰年为 29 天,非闰年为 28 天") default: fmt.Println("输入有误!") } -
选择语句高级写法
switch还有另外一种写法,它包含一个statement可选语句部分,该可选语句在表达式之前运行。它的语法是:switch statement; expression { }可以将上面的例子改写为:
switch month := 5; month { case 1, 3, 5, 7, 8, 10, 12: fmt.Println("该月份有 31 天") case 4, 6, 9, 11: fmt.Println("该月份有 30 天") case 2: fmt.Println("该月份闰年为 29 天,非闰年为 28 天") default: fmt.Println("输入有误!") }
这里 month 变量的作用域就仅限于这个 switch 内。
-
switch 后可接函数
switch后面可以接一个函数,只要保证case后的值类型与函数的返回值一致即可。package main import "fmt" func getResult(args ...int) bool { for _, v := range args { if v < 60 { return false } } return true } func main() { chinese := 88 math := 90 english := 95 switch getResult(chinese, math, english) { case true: fmt.Println("考试通过") case false: fmt.Println("考试未通过") } } -
无表达式的 switch
switch后面的表达式是可选的。如果省略该表达式,则表示这个switch语句等同于switch true,并且每个case表达式都被认定为有效,相应的代码块也会被执行。score := 88 switch { case score >= 90 && score <= 100: fmt.Println("grade A") case score >= 80 && score < 90: fmt.Println("grade B") case score >= 70 && score < 80: fmt.Println("grade C") case score >= 60 && score < 70: fmt.Println("grade D") case score < 60: fmt.Println("grade E") }该
switch-case语句相当于if-elseif-else语句。 -
fallthrough 语句
正常情况下
switch-case语句在执行时只要有一个case满足条件,就会直接退出switch-case,如果一个都没有满足,才会执行default的代码块。不同于其他语言需要在每个case中添加break语句才能退出。使用fallthrough语句可以在已经执行完成的case之后,把控制权转移到下一个case的执行代码中。fallthrough只能穿透一层,不管你有没有匹配上,都要退出了。fallthrough语句是case子句的最后一个语句。如果它出现在了case语句的中间,编译会不通过。s := "从0到Go语言微服务架构师" switch { case s == "从0到Go语言微服务架构师": fmt.Println("从0到Go语言微服务架构师") fallthrough case s == "Go语言微服务架构核心22讲": fmt.Println("Go语言微服务架构核心22讲") case s != "Go语言极简一本通": fmt.Println("Go语言极简一本通") }
11.3 循环语句
循环语句 可以用来重复执行某一段代码。在 C 语言中,循环语句有 for 、 while 和 do while 三种循环。但在 Go 中只有 for 一种循环语句。下面是 for 循环语句的四种基本模型:
// for 接三个表达式
for initialisation; condition; post {
code
}
// for 接一个条件表达式
for condition {
code
}
// for 接一个 range 表达式
for range_expression {
code
}
// for 不接表达式
for {
code
}
接下来我们对每一种模型进行讲解。
-
接一个条件表达式
下面的例子利用
for循环打印0到3的数值:num := 0 for num < 4 { fmt.Println(num) num++ } -
接三个表达式
for后面接的这三个表达式,各有各的用途:- 第一个表达式(
initialisation):初始化控制变量,在整个循环生命周期内,只执行一次; - 第二个表达式(
condition):设置循环控制条件,该表达式值为true时循环,值为false时结束循环; - 第三个表达式(
post):每次循环完都会执行此表达式,可以利用其让控制变量增量或减量。
这三个表达式,使用
;分隔。for num := 0; num < 4; num++ { fmt.Println(num) }该程序的输出和上面的例子是等价的。这里注意一点,在第一个表达式声明的变量
num的作用域只在for循环里面有效。 - 第一个表达式(
-
接一个 range 表达式
在 Go 中遍历一个可迭代的对象一般使用
for-range语句实现,其中range后面可以接数组、切片、字符串等,range会返回两个值,第一个是索引值,第二个是数据值。str := "从0到Go语言微服务架构师" for index, value := range str{ fmt.Printf("index %d, value %c\n", index, value) } -
不接表达式
for后面不接表达式就相当于无限循环,当然,可以使用break语句退出循环。下面两种无限循环的写法等价,但一般使用第一种写法。
// 第一种写法 for { code } // 第二种写法 for ;; { code } -
break 语句
break语句用于终止for循环,之后程序将执行在for循环后的代码。上面的例子已经演示了break语句的使用。 -
continue 语句
continue语句用来跳出for循环中的当前循环。在continue语句后的所有的for循环语句都不会在本次循环中执行,执行完continue语句后将会继续执行一下次循环。下面的程序会打印出10以内的奇数。for num := 1; num <= 10; num++ { if num % 2 == 0 { continue } fmt.Println(num) }
11.4 defer 延迟调用
含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。简单点说就是 defer 语句后面跟着的函数会延迟到当前函数执行完后再执行。
package main
import "fmt"
func bookPrint() {
fmt.Println("Go语言极简一本通")
}
func main() {
defer bookPrint()
fmt.Println("main函数...")
}
首先,执行 main 函数,因为 bookPrint() 函数前有 defer 关键字,所以会在执行完 main 函数后再执行 bookPrint() 函数,所以先打印出 main函数... ,再执行 bookPrint() 函数打印 Go语言极简一本通 。
关于 defer 有几个注意点,下面依次介绍:
-
即时求值的变量快照
使用
defer只是延时调用函数,传递给函数里的变量,不应该受到后续程序的影响。str := "Go语言极简一本通" defer fmt.Println(str) str = "欢喜" fmt.Println(str) -
延迟方法
defer不仅能够延迟函数的执行,也能延迟方法的执行。package main import "fmt" type Book struct { bookName, authorName string } func (b Book) printName() { fmt.Printf("%s %s", b.bookName, b.authorName) } func main() { book := Book{"《Go语言极简一本通》", "欢喜"} defer book.printName() fmt.Printf("main... ") } -
defer 栈
当一个函数内多次调用
defer时,Go 会把defer调用放入到一个栈中,随后按照 后进先出 的顺序执行。package main import "fmt" func main() { defer fmt.Printf("从0到Go语言微服务架构师") defer fmt.Printf("Go语言微服务架构核心22讲") defer fmt.Printf("《Go语言极简一本通》") fmt.Printf("main...") } -
defer 在 return 后调用
package main
import "fmt"
var s string = "Go语言微服务架构核心22讲"
func showLesson() string {
defer func() {
s = "从0到Go语言微服务架构师"
}()
fmt.Println("showLesson: s =", s)
return s
}
func main() {
lesson := showLesson()
fmt.Println("main: s =", s)
fmt.Println("main: lesson =", lesson)
}
-
defer 可以使代码更简洁
如果没有使用
defer,当在一个操作资源的函数里调用多个return时,每次都得释放资源,你可能这样写代码:func f() { r := getResource() //0,获取资源 ...... if ... { r.release() //1,释放资源 return } ...... if ... { r.release() //2,释放资源 return } ...... if ... { r.release() //3,释放资源 return } ...... r.release() //4,释放资源 return }有了
defer之后,你可以简洁地写成下面这样:func f() { r := getResource() //0,获取资源 defer r.release() //1,释放资源 ...... if ... { ... return } ...... if ... { ... return } ...... if ... { ... return } ...... return }
11.5 goto 无条件跳转
在 Go 语言中保留 goto 。goto 后面接的是标签,表示下一步要执行哪里的代码。
goto label
...
label: code
下面是使用 goto 的例子:
package main
import "fmt"
func main() {
fmt.Println("从0到Go语言微服务架构师")
goto label
fmt.Println("Go语言微服务架构核心22讲")
label:
fmt.Println("《Go语言极简一本通》")
}
goto 语句与标签之间不能有变量声明,否则编译错误。编译下面的程序会报错:
package main
import "fmt"
func main() {
fmt.Println("从0到Go语言微服务架构师")
goto label
fmt.Println("Go语言微服务架构核心22讲")
var x int = 0
label:
fmt.Println("《Go语言极简一本通》")
}
联系作者
| 添加微信 | 公众号更多内容 |
|---|---|
![]() |
![]() |












