05 流程控制
三大流程控制语句:
(1) 顺序控制:程序从上到下逐行的执行,中间没有任何判断和跳转。
(2) 分支控制
(3) 循环控制
说明:控制语句可以使用相互嵌套。
格式:
if condition {
statements...
}
说明:
(1) 大括号必须存在,哪怕逻辑块中只有1条语句;
(2) 大括号的左边部分{必须位于条件语句的后面,位于同一行;
(3) Golang中的条件表达式condition无需使用括号包围。当为了区分优先级时,可以使用括号;
(4) Golang中的if语句允许条件判断语句里面声明一个变量,这个变量的作用域是if语句的逻辑块中,在其他地方不起作用;变量声明语句与条件判断语句使用分号分隔。示例:if age := 20 ; age >18 {}
格式:
if condition {
statements...
} else {
statements...
}
说明:
(1) else关键字必须紧跟在}后面,不能单独一行;建议后面的{接在else关键字后面,位于同一行;
格式:
if condition {
statements...
} else if condition {
statements...
} else {
statements...
}
说明:
(1) else if 可以有多个;else是可选的;
(2) 无论是单分支、双分支还是多分支控制语句,都是只有一个执行入口。
switch语句用于条件可以枚举的情况下, 基于不同的条件执行不同的动作。每一个case分支都是唯一的(不能重复),从上往下逐一测试,知道匹配为止。
格式:
switch expression {
case condition1,condition2...: // 可多个condition,中间逗号分隔
statements...
case condition:
statements...
...... // 可以有任意多个case语句
default: // default语句是可选的
statements...
}
说明:
(1) case语句使用冒号结尾;
(2) case后的condition是一个表达式或任何类型的变量(表达式是一个有值的对象。即常量值、变量、一个有返回值的函数等等)。switch后面的的expression也是一个表达式。
(3) case后condition可以有多个,之间使用逗号分隔;各个condition的数据类型必须与switch后面的expression的数据类型一致。常量是无类型的,可以匹配任何类型。
(4) case后condition如果是一个常量值(字面值),则要求多个case间不能有重复的值。如果是变量值,是可以重复的。
(5) Golang中的case语句块不需要写break(这点与bash类似),会默认给添加。即默认情况下,当程序执行完某个case后,就直接退出该switch控制结构(一旦条件符合,自动终止)。
(6) default语句是可选的。
(7) switch后面可以不带表达式(即省略expression),此时case后面使用一个条件表达式。作用类似if-else语句。
func main() {
var age byte = 20
switch {
case age == 10:
fmt.Println("age=10")
case age == 20:
fmt.Println("age=20")
}
}
(8) switch后面也可以直接声明一个变量,分号结束。使用分号分隔expression和声明语句。不推荐,思路不清晰。
func main() {
/*
switch age := 20; {
case age == 10:
fmt.Println("age=10")
case age == 20:
fmt.Println("age=20")
}
*/
switch age := 20; age {
case 10:
fmt.Println("age=10")
case 20:
fmt.Println("age=20")
}
}
(9) swith穿透:在case代码块后使用关键字fallthrough,则会继续执行下一个case,无需判断,可以在多个case中同时使用,默认只穿透一层。
func main() {
switch age := 10; age {
case 10:
fmt.Println("age=10")
fallthrough
case 20:
fmt.Println("age=20")
}
}
/*
输出:
age=10
age=20
*/
完整格式:
for 循环变量初始化; 循环条件; 循环变量迭代 {
循环操作语句(循环体)
}
//此处的循环变量初始化定义的变量作用域为for代码块
示例:
for i := 1; i <= 10; i++ {
fmt.Println("Hello Wrold!")
}
golang中的循环只有for,没有其他语言中的while,do-while,until循环。
for循环语句四要素:循环变量初始化、循环条件、循环变量迭代、循环操作语句(循环体)。前三者都可以省略。通过三者不同组合的省略,可以实现其他语言中的while,do-while,until的效果。
(1)for循环中,变量初始化是可以省略的(但位置需要保留,即变量初始化语句后面的分号需要保留),将变量初始化写在其他位置:
for ; 循环条件; 循环变量迭代 {
循环操作语句(循环体)
}
示例:循环变量省略
i := 1
for ; i <= 10; i++ {
fmt.Println("Hello Wrold!")
}
(2)for循环中,变量初始化、变量迭代语句可以同时省略,只有一个判断条件(将变量初始化、变量迭代写在其他位置),相当于其他语言中的while循环:
for 循环条件 {
循环操作语句(循环体)
}
示例:省略 变量初始化语句、变量迭代语句
i := 1
for i <= 10 {
fmt.Println("Hello Wrold!")
i++
}
(3)for循环中,变量初始化、循环条件、变量迭代语句都省略,成为一个死循环:等价于for ; ; {} ,通常需要配合break语句使用
for {
循环操作语句(循环体)
}
说明:
(1) for循环执行顺序:
1) 循环变量初始化
2) 循环条件
3) 循环操作语句(循环体
4) 循环变量迭代
5) 重复执行2)、3)、4)直到循环条件为false退出循环
(2) 如果再for语句内定义循环变量初始化,定义的变量其作用域为整个for代码块。
(3) 循环条件是一个返回bool值的表达式,循环条件省略是,就成了一个死循环。
(4) Golang中没有while/do-while语句,可以使用for来实现:
while的实现:
循环变量初始化
for 循环条件表达式{
循环操作语句...
循环变量迭代
}
或:
循环变量初始化
for {
if 循环条件表达式 {
break //跳出for循环
}
循环操作语句...
循环变量迭代
}
**do-while的实现: **至少执行1次循环操作语句:
循环变量初始化
for {
循环操作语句...
循环变量迭代
if 循环条件表达式 {
break //跳出for循环
}
}
Golang提供了for-range的方式,用来遍历字符串、数组、切片、map、通道。
通过for-range遍历的返回值有如下规律:
1、数组、slice、map、string返回索引(或key)和值;也可以只有一个返回值,此时返回的是索引(或key)。
2、channel只返回通道内的值。
【注意】for-range在遍历字符串时,是按照字符来遍历的,而不是按照字节。
示例:for-range遍历slice
arr := []int{1, 2, 3, 4}
for index, value := range arr {
fmt.Println("index=", index, " value=", value)
}
示例:传统for循环遍历字符串
str := "hello world!"
for i := 0; i < len(str); i++ {
fmt.Printf("%c\n", str[i])
}
注意上例中,字符串不能有汉字。如果字符串有汉字,则会出现乱码。因为这种遍历字符串的方式是按照字节来遍历的,Golang中处理和保存字符串都是以utf8编码进行的,每个汉字使用3个字节。所以会出现乱码。
如何解决?我们可以使用如下2种方法:
方法1:将字符串转换为[]rune,然后再进行遍历:
str1 := "hello 世界!"
str := []rune(str1) //[]rune整体上是一种类型,表示rune类型的切片
for i := 0; i < len(str); i++ {
fmt.Printf("%c\n", str[i])
}
方法2:可以使用更简便的for-range来遍历字符串:
arr := "hello 世界"
for index, value := range arr {
fmt.Println("index=", index, " value=", string(value)) //遍历字符串时,value是字符,需要使用string函数转换,或者使用printf的%c打印
}
(1) break语句用于终止某个语句块的终止,用于终止for循环和switch语句。终止后直接跳出整个for循环或switch语句。
(2) break语句可以出现在多层嵌套for语句中,在Golang中,break默认是终止当前层(最近一层)语句块,也可以通过标签指明要终止的是哪一层的语句块。
func main() {
lable1: //定义一个标签,名字任意,冒号结尾
for i := 0; i < 4; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
// break
break lable1 // break了lable1标签下面的for语句
}
fmt.Println("j=", j)
}
}
}
(1) continue语句用于结束本次循环,继续执行下次循环。即执行到continue后,不再执行循环体内后面的代码,直接跳转到循环变量迭代。
(2) continue语句出现在多层嵌套的for循环语句中时,可以通过标签指明要跳过的是哪一层的循环。用法同break。
基本语法:
goto label1
....
label1: //定义一个标签,名字任意,冒号结尾
statements
....
说明:
(1) goto可以无条件地转移到程序中指定的行。
(2) goto语句通常与条件语句配合使用。可用来实现条件转移,跳出循环体等功能。
(3) 在Golang程序设计中一般不建议使用goto语句,以免造成程序流程的混乱,使理解和调试程序都产生困难。
示例:
func main() {
var n int = 10
fmt.Println("ok1")
fmt.Println("ok2")
if n == 10 {
goto label1
}
fmt.Println("ok3")
fmt.Println("ok4")
fmt.Println("ok5")
label1:
fmt.Println("ok6")
fmt.Println("ok7")
fmt.Println("ok8")
}
/*
输出:
ok1
ok2
ok6
ok7
ok8
*/