[TOC]
# 流程控制
Go语言中最常用的流程控制有`if`和`for`,而`switch`和`goto`主要是为了简化代码、降低重复代码而生的结构,属于扩展类的流程控制。
## if else(分支结构)
`if`条件判断的格式如下:
~~~
if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else{
分支3
}
~~~
eg1:
~~~
func ifDemo1() {
score := 65
if score >= 90 {
fmt.Println("A")
} else if score > 75 {
fmt.Println("B")
} else {
fmt.Println("C")
}
}
~~~
### if条件判断特殊写法
if条件判断还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断
eg2:
~~~
func ifDemo2() {
if score := 65; score >= 90 {
fmt.Println("A")
} else if score > 75 {
fmt.Println("B")
} else {
fmt.Println("C")
}
}
~~~
还可以进行`if ... else` 的嵌套
## for(循环结构)
所有循环类型均可以使用`for`关键字来完成。
for循环的基本格式如下:
~~~
for 初始语句;条件表达式;结束语句{
循环体语句
}
~~~
条件表达式返回`true`时循环体不停地进行循环,直到条件表达式返回`false`时自动退出循环。
~~~
func Demo() {
for i := 0; i < 10; i++ {
fmt.Println(i)
}
}
~~~
for循环的初始语句可以被忽略,但是初始语句后的分号必须要写,例如:
~~~go
func Demo2() {
i := 0
for ; i < 10; i++ {
fmt.Println(i)
}
}
~~~
for循环的初始语句和结束语句都可以省略,例如:
~~~
func Demo3() {
i := 0
for i < 10 {
fmt.Println(i)
i++
}
}
~~~
这种写法类似于其他编程语言中的`while`,在`while`后添加一个条件表达式,满足条件表达式时持续循环,否则结束循环。
### 无限循环
~~~
for {
循环体语句
}
~~~
for循环可以通过`break`、`goto`、`return`、`panic`语句强制退出循环。
## for range(键值循环)
Go语言中可以使用`for range`遍历数组、切片、字符串、map 及通道(channel)。 通过`for range`遍历的返回值有以下规律:
1. 数组、切片、字符串返回索引和值。
2. map返回键和值。
3. 通道(channel)只返回通道内的值。
## switch case
使用`switch`语句可方便地对大量的值进行条件判断。
~~~
func switchDemo() {
finger := 3
switch finger {
case 1:
fmt.Println("大拇指")
case 2:
fmt.Println("食指")
case 3:
fmt.Println("中指")
case 4:
fmt.Println("无名指")
case 5:
fmt.Println("小拇指")
default:
fmt.Println("无效的输入!")
}
}
~~~
Go语言规定每个`switch`只能有一个`default`分支。
一个分支可以有多个值,多个case值中间使用英文逗号分隔。
~~~
func testSwitch3() {
switch n := 7; n {
case 1, 3, 5, 7, 9:
fmt.Println("奇数")
case 2, 4, 6, 8:
fmt.Println("偶数")
default:
fmt.Println(n)
}
}
~~~
分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量。例如:
~~~
func switchDemo4() {
age := 30
switch {
case age < 25:
fmt.Println("好好学习吧")
case age > 25 && age < 35:
fmt.Println("好好工作吧")
case age > 60:
fmt.Println("好好享受吧")
default:
fmt.Println("活着真好")
}
}
~~~
`fallthrough`语法可以执行满足条件的case的下一个case,是为了兼容C语言中的case设计的。
~~~go
func switchDemo5() {
s := "a"
switch {
case s == "a":
fmt.Println("a")
fallthrough
case s == "b":
fmt.Println("b")
case s == "c":
fmt.Println("c")
default:
fmt.Println("...")
}
}
输出:a
b
~~~
## goto(跳转到指定标签)
`goto`语句通过标签进行代码间的无条件跳转。`goto`语句可以在快速跳出循环、避免重复退出上有一定的帮助。Go语言中使用`goto`语句能简化一些代码的实现过程
~~~
func gotoDemo2() {
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
// 设置退出标签
goto breakTag
}
fmt.Printf("%v-%v\n", i, j)
}
}
return
// 标签
breakTag:
fmt.Println("结束for循环")
}
~~~
## break(跳出循环)
`break`语句可以结束`for`、`switch`和`select`的代码块。
`break`语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的`for`、`switch`和`select`的代码块上。 eg:
~~~
func breakDemo1() {
BREAKDEMO1:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
break BREAKDEMO1
}
fmt.Printf("%v-%v\n", i, j)
}
}
fmt.Println("...")
}
~~~
`注:break + 代码块名称 ` 是一个退出循环的小技巧
## continue(继续下次循环)
`continue`语句可以结束当前循环,开始下一次的循环迭代过程,仅限在`for`循环内使用。
在`continue`语句后添加标签时,表示开始标签对应的循环。
eg:
~~~
func continueDemo() {
forloop1:
for i := 0; i < 5; i++ {
// forloop2:
for j := 0; j < 5; j++ {
if i == 2 && j == 2 {
continue forloop1
}
fmt.Printf("%v-%v\n", i, j)
}
}
}
~~~
`continue + 代码块标签 `和 `break + 代码块名称` 有异曲之处
##select
select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。
~~~
select{
case 条件 :
TODO you want
case 条件 :
TODO you want
/* 你可以定义任意数量的 case */
default:/* 可选 */
TODO you want
}
~~~
select 语句的语法:
* 每个 case 都必须是一个通信
* 所有 channel 表达式都会被求值
* 所有被发送的表达式都会被求值
* 如果任意某个通信可以进行,它就执行,其他被忽略。
* 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。
否则:
1. 如果有 default 子句,则执行该语句。
2. 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。
~~~
packagemain
import"fmt"
func main(){
var c1, c2, c3 chan int
var i1, i2 int
select{
case i1=<-c1:
fmt.Printf("received ",i1," from c1 \n")
case c2 <-i2:
fmt.Printf("sent ",i2," to c2 \n")
case i3,ok:=(<-c3):// same as: i3, ok := <-c3
if ok{
fmt.Printf("received ",i3," from c3 \n")
} else {
fmt.Printf("c3 is closed \n")
}
default:
fmt.Printf("no communication \n")
}
}
~~~
- Go准备工作
- 依赖管理
- Go基础
- 1、变量和常量
- 2、基本数据类型
- 3、运算符
- 4、流程控制
- 5、数组
- 数组声明和初始化
- 遍历
- 数组是值类型
- 6、切片
- 定义
- slice其他内容
- 7、map
- 8、函数
- 函数基础
- 函数进阶
- 9、指针
- 10、结构体
- 类型别名和自定义类型
- 结构体
- 11、接口
- 12、反射
- 13、并发
- 14、网络编程
- 15、单元测试
- Go常用库/包
- Context
- time
- strings/strconv
- file
- http
- Go常用第三方包
- Go优化
- Go问题排查
- Go框架
- 基础知识点的思考
- 面试题
- 八股文
- 操作系统
- 整理一份资料
- interface
- array
- slice
- map
- MUTEX
- RWMUTEX
- Channel
- waitGroup
- context
- reflect
- gc
- GMP和CSP
- Select
- Docker
- 基本命令
- dockerfile
- docker-compose
- rpc和grpc
- consul和etcd
- ETCD
- consul
- gin
- 一些小点
- 树
- K8s
- ES
- pprof
- mycat
- nginx
- 整理后的面试题
- 基础
- Map
- Chan
- GC
- GMP
- 并发
- 内存
- 算法
- docker