鉅細靡遺流程控制,Go lang1.18入門精煉教學,由白丁入鴻儒,Go lang流程結構詳解EP09

2022-08-12 18:02:16

流程結構就是指程式邏輯到底怎麼執行,進而言之,程式執行邏輯的順序。眾所周知,程式整體都是自上由下執行的,但有的時候,又不僅僅是從上往下執行那麼簡單,大體上,Go lang程式的流程控制結構一共有三種:順序結構,選擇結構,迴圈結構。順序結構:從上向下,逐行執行;選擇結構:條件滿足,某些程式碼才會執行,0-1次;迴圈結構:條件滿足,某些程式碼會被反覆的執行多次,0-N次

選擇結構之條件判斷if/else

市面上的語言都有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

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

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 無條件跳轉

使用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亦如此,務實勝過炫技,簡單未必普通。