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 */