1. 判斷語句if
1. 條件表達式沒有括號(這點其他語言轉過來的需要注意)
2. 支持一個初始化表達式(可以是并行方式,即:a, b, c := 1, 2, 3)
3. 左大括號必須和條件語句或 else 在同一行
4. 支持單行模式
5. 初始化語句中的變量為 block 級別,同時隱藏外部同名變量
有關 if 語句示例代碼如下:
package mainimport "fmt"func main() {a := trueif a, b, c := 1, 2, 3; a + b + c > 6 {fmt.Println("大于6")} else {fmt.Println("小于等于6")fmt.Println(a)}fmt.Println(a)if 7 % 2 == 0 {fmt.Println("7 is even")} else {fmt.Println("7 is odd")} }
運行打印結果如下所示:
1 2 3 | 小于等于6 1 true <br>7 is odd |
if 判斷語句比較簡單,只要掌握了相關的語法結構以及上一節講到的相關基礎知識,應用 if 語句也就沒有什么問題了。
2. 循環語句 for
1. Go 只有 for 一個循環語句關鍵字,但是它支持3中形式
2. 初始化和步進表達式可以是多個值
3. 條件語句每次循環都會被重新檢查,因此不建議在條件語句中使用函數,盡量提前計算好條件并以變量或常量代替
4. 左大括號必須和條件語句在同一行
package mainimport (std "fmt" )func main() {/**以下演示for的3種表現形式*/i := 1for i <= 3 { // 類似于java中的:while(i <= 3){}std.Println(i)i = i + 1}for { // 類似于java中的:while(true){}std.Println("while loop")break}for n := 0; n <= 5; n++ { // 類似于java中的:for (int n = 0; n <= 5; n++) {}if n % 2 == 0 {continue}std.Println(n)} }
以上代碼打印結果如下所示:
1 2 3 4 5 6 7 | 1 2 3 while ?loop 1 3 5 |
3. 選擇語句 switch
1. 可以使用任何類型或表達式作為條件語句
2. 不需要寫break,一旦條件符合自動終止
3. 如果希望繼續執行下一個case,需使用 fallthrough 語句
4. 支持一個初始化表達式(可以是并行方式),右側需要跟分號,和 if 條件表達式一樣
5. 左大括號必須和條件語句在同一行
1 package main2 3 import (4 std "fmt"5 "time"6 )7 8 func main() {9 i := 2 10 std.Println("Write number ", i, " as ") 11 switch i { // 基本switch使用 12 case 1: 13 std.Println("one") 14 case 2: 15 std.Println("two") 16 case 3: 17 std.Println("three") 18 default: 19 std.Println("ohter") 20 } 21 22 switch time.Now().Weekday() { // 條件表達式作為判斷條件 23 case time.Saturday, time.Sunday: 24 std.Println("It's the weekend") 25 default: 26 std.Println("It's a weekday") 27 } 28 29 t := time.Now() 30 switch { // 沒有判斷語句則和 if/else 效果一樣 31 case t.Hour() < 12: 32 std.Println("It's before noon") 33 default: 34 std.Println("It's after noon") 35 } 36 37 a := 1 38 switch { 39 case a >= 0: 40 std.Println("a >= 0") 41 fallthrough // 這里不加的話,只會打印 a >= 0,不會向下執行了 42 case a >= 1: 43 std.Println("a >= 1") 44 } 45 }
以上代碼運行結果如下:
1 2 3 4 5 6 | Write number? 2? as two It's a weekday It's after noon a >= 0 a >= 1 |
4. 跳轉語句 goto、break、continue
1. 三個語法都可以配合標簽使用
2. 標簽名區分大小寫,若不使用會造成編譯錯誤
3. break 與 continue 配合標簽可用于多層循環的跳出
4. goto 是調整執行位置,與其他 2 個語句配合標簽的結果并不相同
1 package main2 3 import std "fmt"4 5 func main() {6 LABEL_BREAK:7 for {8 for i := 0; i < 10; i++ {9 if i > 2 { 10 break LABEL_BREAK // 結束循環到指定目標位置 11 } else { 12 std.Println("break number is : ", i) 13 } 14 } 15 } 16 17 LABEL_CONTINUE: 18 for i := 0; i < 10; i++ { 19 for { 20 std.Println(i) 21 continue LABEL_CONTINUE // 結束當前循環層到指定目標位置重新開始 22 } 23 } 24 25 // LABEL_GOTO 如果goto跳轉目標放在這里,則形成了死循環 26 for { 27 for i := 0; i < 10; i++ { 28 if i > 2 { 29 goto LABEL_GOTO // 跳轉到指定目標,從指定目標后開始繼續執行 30 } else { 31 std.Println("goto number is : ", i) 32 } 33 } 34 } 35 LABEL_GOTO: 36 }
以上代碼打印結果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | break ?number is :? 0 break ?number is :? 1 break ?number is :? 2 0 1 2 3 4 5 6 7 8 9 goto ?number is :? 0 goto ?number is :? 1 goto ?number is :? 2 |
?5. 數組 Array
1.? 定義數組的格式:var name [num]type? -->? var a [10]int? (定義1個長度為10類型為int的數組,數組名為 a)
2. 數組長度也是類型的一部分,因此具有不同長度的數組為不同的類型,這點很重要
3. 數組再 Go 中為值類型,故數組之間可以使用 ==、!= 進行比較,但不可以使用 <、> 進行判斷
4. 可以使用 new 來創建數組,此方法返回一個指向數組的指針
5. Go 支持多維數組,但是就和其他語言一樣,不推薦使用
針對數組的基本應用案例如下:
package mainimport "fmt"func main() {var a [5]int // 以為數組的基本應用fmt.Println("emp:", a)a[4] = 100fmt.Println("set:", a)fmt.Println("get:", a[4])fmt.Println("len:", len(a))b := [5]int{1, 2, 3, 4, 5} // 數組初始化并賦值fmt.Println("arrayB:", b)var twoD [2][3]int // 二維數組的應用for i := 0; i < 2; i++ {for j := 0; j < 3; j++ {twoD[i][j] = i + j}}fmt.Println("twoD:", twoD) }
以上代碼打印結果如下所示:
1 2 3 4 5 6 | emp: [0 0 0 0 0] set: [0 0 0 0 100] get: 100 len: 5 arrayB: [1 2 3 4 5] twoD: [[0 1 2] [1 2 3]] |
?那么,這里使用數組采用冒泡排序方式實現對一組數排序功能,代碼如下:
package mainimport ("fmt" )func main() {// 未排序數組,此處使用的變長數組其長度決定于你傳入數據的多少sort := [...]int{1, 7, 4, 2, 5}fmt.Println(sort)// 冒泡排序,由大到小num := len(sort)for i := 0; i < num; i++ {for j := i + 1; j < num; j++ {// 比較大小if sort[i] < sort[j] {temp := sort[i]sort[i] = sort[j]sort[j] = temp}}}fmt.Println(sort) }
以上代碼運行結果如下所示:
1 | [9 7 4 3 2] |
6. 切片 Slice
1. 其本身并不是數組,它指向底層的數組
2. 作為變長數組的替代方案,可以關聯底層數組的局部或全部
3. slice 類型為引用類型
4. 可以直接創建或從底層數組獲取生存
5. 使用 len() 獲取元素個數,cap() 獲取容量
6. 一般使用 make() 創建
7. 如果多個 slice 指向相同底層數組,其中一個的值改變會影響全部
8. make([]T, len, cap)? 其中 cap 可以省略,則和 len 的值相同,len 表示元素的個數,cap 表示當前最大可以存放的容量
1 package main2 3 import "fmt"4 5 func main() {6 // 創建長度為3,容量為3的切片,容量不設置默認為與len相同7 s := make([]string, 3)8 fmt.Println(s)9 10 // 通過操作切片對數組進行賦值 11 s[0] = "a" 12 s[1] = "b" 13 s[2] = "c" 14 fmt.Println("set:", s) 15 fmt.Println("get:", s[2]) 16 17 fmt.Println("len:", len(s), ", cap:", cap(s)) 18 19 // 創建長度為3容量為10類型為int對切片,當放置元素超過10底層會自動翻倍到容量為20,再超再翻倍為49,如此類推 20 s1 := make([]int, 3, 10) 21 fmt.Println("len:", len(s1), ", cap:", cap(s1)) 22 23 s1 = append(s1, 9, 7, 5) 24 fmt.Println("append:", s1) 25 fmt.Println("len:", len(s1), ", cap:", cap(s1)) 26 27 // 實現切片等拷貝 28 c := make([]int, len(s1)) 29 copy(c, s1) 30 fmt.Println("copy:", c) 31 32 // 實現切片上等再切片,類似與python中等截取 33 l := s1[2:5] // 范圍為:[2, 5) 即前閉后開 34 fmt.Println("slice[2:5]:", l) 35 36 l = s1[:5] // 范圍為:[0, 5) 37 fmt.Println("slice[:5]:", l) 38 39 l = s1[2:] // 范圍為:[2, len(s1)) 40 fmt.Println("slice[2:]:", l) 41 42 // 也可以初始化切片時直接賦初始值 43 t := []string{"a", "b", "g", "h", "l"} 44 fmt.Println("init slice:", t) 45 46 // 切片還可以存放不同長度等組合 47 twoD := make([][]int, 3) 48 for i := 0; i < 3; i++ { 49 innerLen := i + 1 50 twoD[i] = make([]int, innerLen) 51 // 為內部數據進行賦值 52 for j := 0; j < innerLen; j++ { 53 twoD[i][j] = i + j 54 } 55 } 56 fmt.Println("towD:", twoD) 57 }
以上代碼運行結果如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | [? ] set: [a b c] get: c len: 3 , cap: 3 len: 3 , cap: 10 append: [0 0 0 9 7 5] len: 6 , cap: 10 copy : [0 0 0 9 7 5] slice[2:5]: [0 9 7] slice[:5]: [0 0 0 9 7] slice[2:]: [0 9 7 5] init slice: [a b g h l] towD: [[0] [1 2] [2 3 4]] |
以上切片代碼,其實可以用下面這張圖片解釋 Slice 與底層數組的對應關系:
切片概念很重要,對后續很多程序都有很大的用處,這里真對切片中幾個重要的概念再著重提一下:
reslice(如上圖中的 Slice_a 和 Slice_b)
1. reslice 時索引以被 slice 的切片為準
2. 索引不可以超過被 slice 的切片的容量 cap() 值
3. 索引越界不會導致底層數組的重新分配而是引發錯誤
說明:這里說的 reslice 代表當前切片是基于數組或 slice 截取生成的,即是它們其中的一部分
append
1. 可以在 slice 尾部增加元素
2. 可以將一個 slice 追加在另外一個 slice 尾部
3. 如果最終長度未超過追加到 slice 的容量則返回原是 slice
4. 如果超過追加到的 slice 的容量則將重新分配數組并拷貝原始數據
copy
1. coyp(dest, source) 兩個參數代表將第二個參數代表的切片拷貝給第一個參數代表的切片
?小總結:Array 與 Slice 之間的區別
數組Array所有使用案例如下:
var ?m [3]int?????????????? // 定義了一個長度為3的int數組,元素值都為0 m:= [3]int{}???????????? // 聲明了一個長度為3的int數組,元素值都為0 a := [3]int{1, 2, 3}?? // 聲明了一個長度為3的int數組 b := [10]int{1, 2, 3} // 聲明了一個長度為10的int數組,其中前三個元素初始化為1、2、3,其它默認為0 c := [...]int{4, 5, 6}??? // 可以省略長度而采用 "..." 的方式,Go會自動根據元素個數來計算長度??? |
? 切片Slice所有使用案例如下:
var ?m []int??????? // 聲明了一個指向底層數組的切片 m:= []int{}??????? // 聲明了一個指向底層數組的切片 a := array[2:5]??? // a指向數組的第3個元素開始,并到第五個元素結束的切片 b := array[:5] // b指向數組的第0個元素開始,并到第五個元素結束的切片 c := array[2:]???? // c指向數組的第2個元素開始,并到最后一個元素結束的切片 d := b[3:]??? // d指向切片的第3個元素開始,并到最后一個元素結束的切片(即可以切片嵌套) |
由上面的結果可以看出,聲明數組時,方括號內寫明了數組的長度或使用...自動計算長度,而聲明?slice時,方括號內沒有任何字符。