Go语言--第4章 流程控制
主要内容
- 4.1 条件判断--if
- 4.2 构建循环--for
- 4.3 示例:九九乘法表
- 4.4 键值循环(for range)-- 直接获得对象的索引和数据
- 4.5 分支选择(switch) -- 拥有多个条件分支的判断
- 4.6 跳转到指定代码标签(goto)
- 4.7 跳出指定循环(break)
- 4.8 跳出当前循坏(continue)
Go语言规定与if匹配的左括号“{” 必须与if 和表达式放在同一行
,如果尝试将“{”放在其他位置,将会触发编译错误
与else 匹配的 “{” 也必须与else 在同一行
else也必须与上-个if 或else if 的右边的大括号在一行
格式:
if 表达式1 { 分支1 } else if 表达式2 { 分支2 } else { 分支3 } // > 10
特殊写法
if 还有特殊的写法,可以在if表达式之前添加一个执行语句,再根据变量值进行判断,如:
if err := Connect(); err != nil { fmt.Println(err) return }
Connect() 为假设的函数,err := Connect() 可以视为一个表达式
4.2 构建循环--for
Go语言中所有循环类型均可以使用for关键字完成
for 初始语句;条件表达式; 结束语句 {
循环体代码
}
for 循环可以通过break
,goto
,return
,panic
语句强制退出循环
4.2.1 for中初始语句--开始执行的语句
初始语句可以被忽略,但是初始语句之后的分号必须要写
step := 2 for ; step > 0; step-- { fmt.Println(step) } // 2 // 1
4.2.2 for中条件表达式--控制是否循环的开关
条件表达式也可以被忽略,忽略默认为无限循环
-
结束循环时带可执行语句的无限循环
var i int for ; ; i++ { if i > 10 { fmt.Println("i > 10") break; } } // i > 10
-
无限循环
for { if i > 10 { fmt.Println("i > 10") break } i++ } // i > 10
4.2.3 for中结束语句--每次循环结束时执行的语句
在结束每次循环前执行的语句,被break 、goto、return、panic等语句强制推出
示例:
// 遍历九九乘法表 for x:=1; x < 10; x++ { for y :=1; y <= x; y++ { sum := x * y fmt.Printf("%d * %d = %d ", x, y, sum ) } fmt.Printf("\r\n") } 结果 1 * 1 = 1 2 * 1 = 2 2 * 2 = 4 3 * 1 = 3 3 * 2 = 6 3 * 3 = 9 4 * 1 = 4 4 * 2 = 8 4 * 3 = 12 4 * 4 = 16 5 * 1 = 5 5 * 2 = 10 5 * 3 = 15 5 * 4 = 20 5 * 5 = 25 6 * 1 = 6 6 * 2 = 12 6 * 3 = 18 6 * 4 = 24 6 * 5 = 30 6 * 6 = 36 7 * 1 = 7 7 * 2 = 14 7 * 3 = 21 7 * 4 = 28 7 * 5 = 35 7 * 6 = 42 7 * 7 = 49 8 * 1 = 8 8 * 2 = 16 8 * 3 = 24 8 * 4 = 32 8 * 5 = 40 8 * 6 = 48 8 * 7 = 56 8 * 8 = 64 9 * 1 = 9 9 * 2 = 18 9 * 3 = 27 9 * 4 = 36 9 * 5 = 45 9 * 6 = 54 9 * 7 = 63 9 * 8 = 72 9 * 9 = 81
4.4 键值循环(for range)-- 直接获得对象的索引和数据
Go语言可以使用for range遍历、数据、切片、字符串、map及通道(channel)
规律:
-
数组、切片、字符串返回索引值
-
map返回键和值
-
通道(channel)只返回通道内的值
4.4.1 遍历数组、切片--获得索引和元素
for key, value := range []int{1,2,3,4} { fmt.Printf("key: %d, value: %d\r\n", key, value ) } //key: 0, value: 1 //key: 1, value: 2 //key: 2, value: 3 //key: 3, value: 4
4.4.2 遍历字符串--获得字符
for key, value := range "abcdef" { fmt.Printf("key: %d, value: 0x%x\r\n", key, value ) } //key: 0, value: 0x61 //key: 1, value: 0x62 //key: 2, value: 0x63 //key: 3, value: 0x64 //key: 4, value: 0x65 //key: 5, value: 0x66
4.4.3 遍历字典map--获得键和值
m := map[int]string{ 1 : "one", 2 : "two", 3 : "three", } for key,value := range m { fmt.Printf("key: %d, value: %s\r\n", key, value ) } // key: 1, value: one // key: 2, value: two // key: 3, value: three
4.4.3 遍历通道channel -- 接受通道数据
c := make(chan int) // 启动一个goroutine,往通道中推送数据1、2、3,然后关闭通道 go func() { c <- 1 c <- 2 c <- 3 close(c) }() for v := range c { fmt.Println(v) } // 1 // 2 // 3
4.4.5 遍历中只选择需要的变量
不需要获得的key或value,可以用下划线“-”
代替,即匿名变量
匿名变量,可理解为占位符,本身不会进行空间分配,不会占用变量的名字
for _, value := range []int{1,2,3,4} { fmt.Printf("value: %d\r\n", value ) } // value: 1 // value: 2 // value: 3 // value: 4
4.4.6 for总结
for 功能:
-
Go语言for包含初始条件,条件表达式、结束语句,这3个均可省略
-
for range 支持数组、切片、字符串、map、通道遍历
-
可使用匿名变量获取只需要的变量
4.5 分支选择(switch) -- 拥有多个条件分支的判断
4.5.1 基本写法
switch中每个case与case间是独立的代码块,不需要通过break语句跳出当前case代码块以避免执行到下一行
Go语言规定每一个switch只能有一个default分支
var a = "hello" switch a { case "hello": fmt.Println(1) case "world": fmt.Println(2) default: fmt.Println(0) }
分支常见情况:
-
一分支多值
switch a { case "hello", "world" : fmt.Println("Hi") }
-
分支表达式
var r int = 11 var s int = 5 switch { case r > 10 && r <20: fmt.Println(r) case s > 2 && s <10: fmt.Println(s) } // 11
如果只有一个变量判断的时候,switch后面可以不用添加变量r
4.5.2 跨越case的fallthrough -- 兼容c语言的case设计
fallthrough
关键字用来实现case分支间的执行,应为go语言的case的是独立的代码块
str := "hello" switch { case str == "hello": fmt.Println("hello") fallthrough case str != "world": fmt.Println("world") } // hello // world
4.6 跳转到指定代码标签(goto)
goto语句通过标签进行代码间的无条件跳转,可以快速跳出循环避免重复退出上有一定帮助
4.6.1 使用goto退出多层循环
原代码:
packeage main import ("fmt") func main() { var breakAgain bool for x := 0; x < 10; x++ { for y := 0; y <10; y++ { if y == 2 { breakAgain = true break } } if breakAgain { break } } fmt.Println("done") }
使用goto语句进行优化:
使用goto语句后,无须额外的变量就可以进行快速退出所有的循环
packeage main import ("fmt") func main() { for x := 0; x < 10; x++ { for y := 0; y <10; y++ { if y == 2 { // 跳转到标签 goto breakHere } } } // 手动返回,避免执行进入标签 return // 标签 breakHere: fmt.Println("done") }
4.6.2 统一错误处理
err := firstCheckError() if err != nil { goto onExit } err = secondCheckError() if err != nil { goto onExit } fmt.Println("done") return onExit: fmt.Println(err)
4.7 跳出指定循环(break)
break语句可以跳出for 、switch 和select代码块
break语句后面添加标签,表示退出某个标签对应的代码块,标签必须定义在对应的for、switch和select的代码块上
packeage main import ("fmt") func main() { loop: for i:=1; i<=3; i++ { for j := 0; j<5;j++ { switch j { case 2: fmt.Println(i,j) // 退出 loop标签下的这个双循坏代码 break loop case 3: fmt.Println(i,j) break loop } } } }
4.8 跳出当前循坏(continue)
continue语句结束当前循坏,开始下一个循环,仅限于for循环内使用
continue语句后面添加标签时,表示开始标签对应的循环
packeage main import ("fmt") func main() { loop: for i:=0; i<=3; i++ { for j := 0; j<5;j++ { switch j { case 2: fmt.Println(i,j) continue loop } } } // 0 2 // 1 2 // 2 2 // 3 2 }