流程結構就是指程式邏輯到底怎麼執行,進而言之,程式執行邏輯的順序。眾所周知,程式整體都是自上由下執行的,但有的時候,又不僅僅是從上往下執行那麼簡單,大體上,Go lang程式的流程控制結構一共有三種:順序結構,選擇結構,迴圈結構。順序結構:從上向下,逐行執行;選擇結構:條件滿足,某些程式碼才會執行,0-1次;迴圈結構:條件滿足,某些程式碼會被反覆的執行多次,0-N次
市面上的語言都有if/else邏輯,邏輯非常簡單,只要滿足條件,就會執行條件程式碼塊的邏輯:
if 布林表示式 {
/* 在布林表示式為 true 時執行 */
}
if 布林表示式 {
/* 在布林表示式為 true 時執行 */
} else {
/* 在布林表示式為 false 時執行 */
}
if 布林表示式1 {
/* 在布林表示式1為 true 時執行 */
} else if 布林表示式2{
/* 在布林表示式1為 false ,布林表示式2為true時執行 */
} else{
/* 在上面兩個布林表示式都為false時,執行*/
}
具體邏輯:
package main
import "fmt"
func main() {
var a int = 1
/* 使用 if 語句判斷布林表示式 */
if a < 20 {
/* 如果條件為 true 則執行以下語句 */
fmt.Printf("a 小於 20\n")
}
fmt.Printf("a 的值為 : %d\n", a)
}
程式返回:
a 小於 20
a 的值為 : 1
需要注意的是,條件變數型別要一致才能比較。
除此之外,if還可以在判斷之前執行邏輯:
package main
import (
"fmt"
)
func main() {
if num := 10; num%2 == 0 { //checks if number is even
fmt.Println(num, "is even")
} else {
fmt.Println(num, "is odd")
}
}
程式返回:
10 is even
也就是說,當判斷變數num對2取餘是否等於0之前,我們可以先給num進行賦值操作。
同時if/else也支援多分支判斷:
package main
import (
"fmt"
)
func main() {
score := 88
if score >= 90 {
fmt.Println("成績等級為A")
} else if score >= 80 {
fmt.Println("成績等級為B")
} else if score >= 70 {
fmt.Println("成績等級為C")
} else if score >= 60 {
fmt.Println("成績等級為D")
} else {
fmt.Println("成績等級為E 成績不及格")
}
}
程式返回:
成績等級為B
這裡程式根據變數的值而選擇執行不同的分支程式碼,但需要注意的是,Go lang對於 { 和 } 的位置有嚴格的要求,它要求 else if (或 else ) 和兩邊的花括號,必須在同一行。即使在 { 和 } 之間只有一條語句,這兩個花括號也是不能省略的。
switch關鍵字是一個條件語句,它計算表示式並將其與可能匹配的列表進行比較,並根據匹配執行程式碼塊。它可以被理解為用一種普適的方式來寫多個if else判斷子句。
switch 語句用於基於不同條件執行不同動作,每一個 case 分支都是唯一的,從上直下逐一測試,直到匹配為止。 switch 語句執行的過程從上至下,直到找到匹配項,匹配項後面也不需要再加break。
說白了就是,每一個case都預設自動break,執行完了一個,switch邏輯也就結束了,不會順序執行別的case,但是可以使用fallthrough強制執行後面的case程式碼:
package main
import "fmt"
func main() {
/* 定義區域性變數 */
var grade string = "B"
var marks int = 40
switch marks {
case 90:
grade = "A"
case 80:
grade = "B"
case 50, 60, 70:
grade = "C" //case 後可以由多個數值
default:
grade = "D"
}
switch {
case grade == "A":
fmt.Printf("A\n")
case grade == "B", grade == "C":
fmt.Printf("B\n")
case grade == "D":
fmt.Printf("D\n")
case grade == "F":
fmt.Printf("F\n")
default:
fmt.Printf("low\n")
}
fmt.Printf("你的等級是 %s\n", grade)
}
程式返回:
D
你的等級是 D
這裡我們先通過switch對marks變數進行值判斷,在case分支裡賦值grade變數,隨後又在switch邏輯中對grade做恆等判斷,然後輸出。
假設需要貫通後續的case,就新增fallthrough關鍵字:
package main
import (
"fmt"
)
func main() {
switch x := 5; x {
default:
fmt.Println(x)
case 5:
x += 10
fmt.Println(x)
fallthrough
case 6:
x += 20
fmt.Println(x)
}
}
這裡首先進入case5邏輯,x經過運算後變為15,隨後貫通進入下一個邏輯,x += 20 邏輯,變為35。
程式返回:
15
35
需要注意的是,fallthrough應該是某個case的最後一行。如果它出現在中間的某個地方,編譯器就會丟擲錯誤。
for關鍵字可以用來重複執行某一段程式碼,在Python中,遍歷方式有三種:for 、 while 和 do while 。但是Go lang只為我們提供了一種:for:
package main
import (
"fmt"
)
func main() {
num := 1
for num < 3 {
fmt.Println(num)
num++
}
}
程式返回:
1
2
這裡是但條件迴圈,如果滿足條件,for程式碼塊的邏輯會重置執行。
我們還可以為遍歷新增額外的表示式邏輯,比如初始化控制變數,在整個迴圈生命週期內,只執行一次;設定迴圈控制條件,該表示式值為 true 時迴圈,值為 false 時結束迴圈;每次迴圈完都會執行此表示式,可以利用其讓控制變數增量或減量:
package main
import (
"fmt"
)
func main() {
for num := 0; num < 4; num++ {
fmt.Println(num)
}
}
程式返回:
0
1
2
3
需要注意的是,在for關鍵字中宣告的變數,也只在for的程式碼塊中有效,因為和Python不同,go lang有嚴格的塊作用域限制。
在 Go lang中遍歷一個可迭代的物件一般使用 for-range 語句實現,其中 range 後面可以接陣列、切片、字串等, range 會返回兩個值,第一個是索引值,第二個是資料值:
package main
import (
"fmt"
)
func main() {
str := "123456789"
for index, value := range str {
fmt.Printf("index %d, value %c\n", index, value)
}
}
程式返回:
index 0, value 1
index 1, value 2
index 2, value 3
index 3, value 4
index 4, value 5
index 5, value 6
index 6, value 7
index 7, value 8
index 8, value 9
如果for關鍵字後面沒有表單式,就是死迴圈:
package main
import (
"fmt"
)
func main() {
num := 1
for {
fmt.Println(num)
num++
if num > 3 {
break
}
}
}
程式返回:
1
2
3
是的,我們當然可以使用break關鍵字來中斷迴圈。
但需要注意的是,break只能終端當前迴圈,不能終端外部迴圈:
package main
import "fmt"
func main() {
/* 定義區域性變數 */
var i, j int
for i = 2; i < 10; i++ {
for j = 2; j <= (i / j); j++ {
if i%j == 0 {
break // 如果發現因子,則不是素數
}
}
if j > (i / j) {
fmt.Printf("%d 是素數\n", i)
}
}
}
程式返回:
2 是素數
3 是素數
5 是素數
7 是素數
和Python一樣,Go lang也具備continue關鍵字,continue 語句用來跳出 for 迴圈中的當前回圈:
package main
import "fmt"
func main() {
for num := 1; num <= 10; num++ {
if num%2 == 0 {
continue
}
fmt.Println(num)
}
}
程式返回:
1
3
5
7
9
在 continue 語句後的所有的 for 迴圈語句都不會在本次迴圈中執行,執行完 continue 語句後將會繼續執行一下次迴圈。這樣我們就可以跳過偶數,直接列印出 10 以內的奇數。
使用goto關鍵字可以直接跳到下一步要執行的標籤程式碼:
package 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")
}
程式返回:
done
需要注意的是,goto關鍵字與標籤之間不能有變數宣告,否則編譯錯誤。
和Python和Ruby相比,整體上,在流程結構控制環節,Go lang表現出了極大的剋制,語法上刪繁就簡, 把動態語言那些桀驁不馴的語法糖壓制成行文工整的詩,這樣的好處是對初學者極為友好,沒有太多規範需要記憶,大道至簡,大巧不工。我們可以吐槽它沒有while或者是do while,亦或者是lambda表示式等可以炫技的資本,但,那又如何呢?就像喬幫主在聚賢莊力戰群雄,大殺四方,所倚重的不過是一套普普通通的太祖長拳,Go lang亦如此,務實勝過炫技,簡單未必普通。