Go语言没有do-while语句,而for语句拥有更普遍的含义和用途switch语句也有进一步的扩展,支持类型判断和初始化子句等。编程
常见的流程控制的关键字有:数组
func main() { a := 15 if a < 20 { fmt.Println("a小于20") } //顺序执行 fmt.Println("a的值是", a) }
if判断语句是最简单的判断,缺点在于没法返回false的状况,为了增长这一功能就要用到if-else语句。并发
func main() { a := 20 if a < 20 { fmt.Println("a小于20") } else { fmt.Println("a大于等于20") } }
若是想判断a值是否大于10同时小于20时,if-else语句就不可以知足需求了。避免使用嵌套if-else语句,由于实现逻辑复杂,使得代码可读性较差。接下来要提到到的else-if语句能够很好的解决这个问题。异步
//判断a值是否在区间(10,20) func main() { a := 15 if a > 20 { fmt.Println("a大于20") } else if a < 10 { fmt.Println("a小于10") } else { fmt.Println("a小于20") fmt.Println("a大于10") } fmt.Println("a的值为:", a) } /* a小于20 a大于10 a的值为: 15 */
else-if语句可使用多个else-if关键字函数
func main() { a := 13 if a > 20 { fmt.Println("a大于20") } else if a < 10 { //else-if语句后 fmt.Println("a小于10") } else if a == 15 { fmt.Println("a等于15") } else { fmt.Println("a小于20") fmt.Println("a大于10") fmt.Println("a不等于15") } fmt.Println("a的值为:", a) } /* a小于20 a大于10 a不等于15 a的值为: 13 */
switch表示选择语句的关键字,根据初始化表达式得出一个值,而后根据case语句的条件,执行相应的代码块,最终返回特定内容。
若是没有遇到特定的case,则可使用default case;若是已经遇到符合条件的case,那么后面的case都不会被执行。
在Go语言中,switch有两种类型学习
func main() { score := 90 level := "C" switch score { //对应表达式的值选择case case 90: level = "A" case 80: level = "B" case 70: level = "C" case 60: level = "D" default: level = "NULL" } fmt.Printf("你的等级是%s\n", level) }
这种语句写法虽然简单,可是缺点也很明显,缘由是它直能判断单值的case,对于除了固定的case之外的值,全都被返回到了default,使得输出数据变得不合理。例如,socre值为91,却打印出“你的等级是NULL”。code
为了解决这一问题,咱们可使用完整的switch表达式,同时容许多个switch语句相互关联,好比下面的代码块,容许第二个switch语句接收第一个switch语句返回值做为选择条件。索引
func main() { score := 90 level := "C" switch score { //判断成绩所属区间 case 90: level = "A" case 80: level = "B" default: level = "NULL" } switch { //能够接受上一个switch语句的case值,switch语句后的条件表达式不限制为常量或表达式,容许什么都不写 case level == "A": fmt.Println("优秀") //单个case能够多个结果选项 fmt.Println("Good!") case level == "B": fmt.Println("良好") default: fmt.Println("你的成绩不存在!") } fmt.Println("你的成绩是:", score) } /* 优秀 Good! 你的成绩是: 90 */
咱们能够总结出Go语言的switch语句有如下特色:接口
/*fallthrough写法*/ func main() { score := 80 level := "B" switch score { //对应表达式的值选择case case 90: level = "A" case 80: level = "B" fallthrough //把当前case控制权交给下一个语句判断,当前case语句被忽略 default: level = "NULL" } fmt.Printf("你的等级是%s\n", level) } /* 你的等级是NULL */
以上语句score等于80,正常来看会选择对应case值80的选择语句,可是fallthrough关键字会忽略本层case语句的选择条件,强制执行下一个case语句的内容(无论什么条件都会被执行),因此输出的内容是default的选择语句。资源
类型switch语句能够根据条件表达式的类型自动选择执行哪一个case代码块。使用类型switch语句时,须要判断的变量必须是接口类型的变量。有关接口的知识点将在之后的学习补充和完善。
注意:type-switch语句不容许使用fallthrough
type Element interface{} //声明接口类型 func main() { var e Element = "这是一个字符串" switch value := e.(type) { //根据类型选择对应case语句 case int: fmt.Println("int", value) case string: fmt.Println("string", value) default: fmt.Println("unknown", value) } } /* string 这是一个字符串 */
一样的,switch语句后面也能够写上初始化表达式,而且只能有一句语句。
(待补充)
在选择语句中,除了switch语句,还有另外一种select语句,这种语句用于配合通道(channel)的读写操做,用于多个channel的并发读写特性。有关并发的特性将在后面的学习中介绍。**switch语句是按顺序从上到下依次执行的,select语句是随机判断一个case来判断,直到匹配其中的一个case为止。
package main import ( "fmt" ) //并发编程的内容 func main() { a := make(chan int, 1024) b := make(chan int, 1024) for i := 0; i < 10; i++ { fmt.Printf("第%d次", i) a <- 1 // b <- 1 select { case <-a: fmt.Println("from a") case <-b: fmt.Println("from b") } } }
在Go语言中,循环语句的关键字是for,没有while关键字。for语句能够根据指定的条件重复执行其内部的代码块,这个判断条件通常是由for后面的子语句给出的。
for语句后面的三个子语句咱们称为:初始化子语句、条件子语句、后置子语句,这三个子语句顺序不能颠倒,其中条件子语句是必需的,条件子语句会返回一个布尔型,true执行代码块,false则跳出循环。
func main() { a := 0 b := 5 for a < b { //只有条件子语句,实际是 for ; a<b ; 的简写 a++ fmt.Println("a的值是:%d", a) } } /* a的值是:%d 1 a的值是:%d 2 a的值是:%d 3 a的值是:%d 4 a的值是:%d 5 */
每个for语句均可以使用一个特殊的range子语句,其做用相似迭代器,用于轮询数组或者切片值的每个元素,也能够用于轮询字符串的每个字符串和字典值中的键值对,甚至还能够持续读取一个通道类型值中的元素。
注意:range关键字左边表示是一对索引-值对
package main import ( "fmt" ) func main() { str := "asdf" for i, char := range str { //range关键字右边是range表达式,表达式通常写在for语句前面,提升代码可读性 fmt.Printf("这是第%d个字符串的值是:%d\n", i, char) } for _, char := range str { fmt.Println(char) //使用空标识符_屏蔽索引值,只打印字符值 } for i := range str { fmt.Println(i) //使用空标识符_屏蔽字符值,只打印索引值 } for range str { fmt.Println("轮询完毕") } } /* 这是第0个字符串的值是:97 这是第1个字符串的值是:115 这是第2个字符串的值是:100 这是第3个字符串的值是:102 97 115 100 102 0 1 2 3 轮询完毕 轮询完毕 轮询完毕 轮询完毕 */
对于空字典或切片、空数组、空字符串等状况,for语句会直接结束,不会循环。
func main() { str := "" //空字符串 for i, char := range str { //只有条件子语句 fmt.Printf("这是第%d个字符串的值是:%d\n", i, char) } for _, char := range str { fmt.Println(char) //值对 } for i := range str { fmt.Println(i) //索引 } for range str { fmt.Println("轮询完毕") } fmt.Println("这是一个空字符串") //字符串为空,跳出for循环 } /* 这是一个空字符串 */
在Go语言中,除了上述提到的常规流程控制的语句以外,还有一些特殊的控制语句,也是Go语言的语法特性之一。defer语句就是其中一个,用于延迟调用指定函数,defer关键字只能出如今函数内部,而且只能用于调用外部函数。例如,以下的代码块,defer就是 fmt.Println 外部函数的延迟调用,被延迟的操做是defer后面的语句。
func main() { defer fmt.Println("请延迟执行这条语句") //defer关键字只能出现于函数内部,而且用于外部函数的调用 fmt.Println("请先执行这条语句") } /* 请先执行这条语句 请延迟执行这条语句 */
defer 有两大特色:
当函数中有defer语句时,须要等待全部defer语句执行完毕,才会执行return语句。
/*利用defer特性打印反向数字列表*/ var i int = 0 func print(i int) { //构造打印函数 fmt.Println(i) } func main() { for ; i < 5; i++ { //省略初始化子语句 defer print(i) //因为defer的延迟特性,知足先进后出,因此可将defer当作一个栈,依次打印出栈顺序 } } /* 4 3 2 1 0 */
在Go语言中,还有一个特殊的概念那就是标签(相似汇编语言),能够给for、switch、select语句等流程控制代码块打上一个标签,配合标签标识符能够方便跳转到某一个地方继续执行,有助于提升编程效率。
func main() { LOOP1: //标签 for i := 0; i < 5; i++ { switch { case i < 5: fmt.Println("A") break LOOP1 //跳到标签LOOP1,处于for循环之外,再也不执行任务 case i == 5: fmt.Println("B") } fmt.Println("i的值是:", i) //因为使用break跳转到标签LOOP1,此条语句再也不执行 } }
A
*/
为了提升代码的可读性,建议标签名称使用大写字母和数字。标签能够标记任何语句,并不限定于流程控制语句,**未使用的标签会引起错误**。 ### break语句 break语句用于打断当前流程控制,例如:
package main
import (
"fmt"
)
func main() {
for i := 0; i < 10; i++ { fmt.Println("i的值是:", i) if i > 4 { break //打断,跳出当前for循环 } }
}
/*
i的值是: 0
i的值是: 1
i的值是: 2
i的值是: 3
i的值是: 4
i的值是: 5
*/
对于嵌套流程控制语句,break只能中断当前循环,不能跳出外层循环。
package main
import (
"fmt"
)
func main() {
for i := 0; i < 5; i++ { switch { case i < 5: fmt.Println("A") break //跳出当前switch循环,未跳出外层for循环 case i == 5: fmt.Println("B") } fmt.Println("i的值是:", i) }
}
/*
A
i的值是: 0
A
i的值是: 1
A
i的值是: 2
A
i的值是: 3
A
i的值是: 4
*/
### continue语句 与break语句相反,continue语句则用于跳转到指定代码块或标签位置**继续执行任务,且只能用于for循环**。
func main() {
LOOP1: //标签
for i := 0; i < 5; i++ { switch { case i < 5: fmt.Println("A") continue LOOP1 //跳到标签LOOP1,处于for循环之外,继续执行任务 case i == 5: fmt.Println("B") } fmt.Println("i的值是:", i) / }
}
/*
A
A
A
A
A
*/
### goto语句 goto语句用于**无条件跳转到相同函数的带标签语句,且只能在同一函数跳转**。
func main() {
for i := 0; i < 3; i++ { fmt.Println("A") goto LOOP2 //跳到标签LOOP2 fmt.Println("B") //忽略不执行 LOOP2: fmt.Println("i的值是:", i) //顺序执行 }
}
/* A i的值是: 0 A i的值是: 1 A i的值是: 2 */