從測試中學習 Go 語言 (資料集合篇)

Array

  • 大小固定,宣告後即無法變更

  • 存放的元素在記憶體中是連續的

  • 使用時機:

    • 當元素數量在編譯時固定且已知時
    • 需要直接存取記憶體時
    • 需要更好的效能或直接記憶體存取時
  • examples

    • 作為演算法中的向量、矩陣或固定大小的緩衝區
    • 定義硬體介面或低階程式設計中所使用的資料結構的形狀
  • 長度是其類型的一部分

    1
    2
    
      var arr [5]int
      arr = [2]int{1,2} // compile error : [2]int 與 [5]int 視為不同的類型
    

Declaration

DeclarationValues
arr := [5]int{1, 2, 3, 4, 5}[1 2 3 4 5]
arr := [...]int{1, 2, 3, 4, 5}[1 2 3 4 5]
var arr [5]int[0 0 0 0 0]
arr := [5]int{1: 10, 3: 30}[0 10 0 30 0]

Operation

OperationCode SnippetOutput
Declarationarray := [5]int{1, 2, 3, 4, 5}[1 2 3 4 5]
Lengthlen(array)5
CreateNot applicable to arrays
Readarray[2]3
Updatearray[2] = 10[1 2 10 4 5]
DeleteNot applicable to arrays
Iterationfor index, value := range array
{...}
can ignore the index value by using _ blank identifier

Slice

  • 可動態調整長度
  • 存放的元素在記憶體中是連續的
  • 使用 append 回傳新的 Slice 用來刪除元素
  • 使用時機:
    • 當元素的數量是動態的或在編譯時未知時
    • 處理可變長度資料時,例如來自外部來源的輸入 (parameters from function input)
    • 需要靈活管理可成長或縮減的集合時
  • examples
    • 處理可變長度序列時
    • 實作 stack、 queue 或 dynamic array 等資料結構時

Declaration

DeclarationValues
slice := []int{1, 2, 3, 4, 5}[1 2 3 4 5]
slice := make([]int, 5)[0 0 0 0 0]
slice := make([]int, 0, 5)[]
arr := [...]int{1, 2, 3, 4, 5}; slice := arr[1:4][2 3 4]
slice := []int{}[]

Operation

OperationCode SnippetOutput
Declarationslice := []int{1, 2, 3, 4, 5}[1 2 3 4 5]
Lengthlen(slice)5
Createslice = append(slice, 6)[1 2 3 4 5 6]
Readslice[2]3
Updateslice[2] = 10[1 2 10 4 5 6]
Deleteindex := 2
slice = append(slice[:index], slice[index+1:]...)
[1 2 4 5 6]
Iterationfor index, value := range slice
{...}
can ignore the index value by using _ blank identifier

Map

  • 可動態調整長度

  • 存放的元素在記憶體中是不連續的

  • 使用 delete 刪除元素

  • 本質上是一個指標,當其被放入 function/method 時,是複製指標,而非指向的真實的資料

  • 使用時機:

    • 作為 disctionary、hash table 時
    • 當處理需要透過唯一鍵索引的資料集合時
    • 用於儲存鍵和值之間的關係很重要的資料
  • examples

    • 基於唯一識別碼建立查找表以實現高效的資料檢索
    • 實現快取以快速存取經常存取的資料
  • 用 key 去查找 map 映射的值時,有兩個回傳值 (value, ok)

    • value, ok := myMap[key]
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    m := map[string]int{"one": 1, "two": 2, "three": 3}
    
    value, ok := m["zero"] 
    // if 只要查 key 是否有在裡面可用 _ 不檢索其值
    // _, ok := m["zero"]
    
    if ok {
      fmt.Println("Value:", value)
    } else {
      fmt.Println("Key not found", value) // value == 0
    }

Declaration

DeclarationValues
m := map[string]int{"one": 1, "two": 2, "three": 3}{“one”: 1, “two”: 2, “three”: 3}
m := make(map[string]int){}
m := map[string]int{}{}

Operation

OperationCode SnippetOutput
Declarationm := map[string]int{"one": 1, "two": 2, "three": 3}map[four:4 one:1 three:3 two:2]
Lengthlen(m)3
Createm["four"] = 4map[four:4 one:1 three:3 two:2]
Readm[two]
value, ok := m[two]
value, ok := m[zero]
2
value: 2, ok: true
value: 0, ok: false
Updatem["two"] = 20map[four:4 one:1 three:3 two:20]
Deletedelete(m, "three")map[four:4 one:1 two:20]
Iterationfor key, value := range m
{...}
can ignore the key value by using _ blank identifier

比較資料集合是否相同

  • reflect 套件 DeepEqual 函式:reflect.DeepEqual(A, B)

    • 可用來比較 array, slice , map 型態
    • 原理是用遞回的方式比較 A, B 兩個值的元素,如果它們深度相等則傳回 true
    • 使用時不會預先檢查比較的 A, B 型態是否相同
    • 用於大型資料結構時,需注意效能影響
    1
    2
    3
    4
    5
    6
    7
    8
    
    import "reflect"
    
    got := "test"
    want := []int{0, 9}
    
    if !reflect.DeepEqual(got, want) {
          t.Errorf("got %v want %v", got, want)
    } // raise an error
    
  • slices.Equal(A, B)

    • GO 1.21 後的標準 package
    • 用來比較 A, B 兩個值的元素,其長度與內容是否相同
    • 使用時會預先檢查比較的 A, B 型態是否相同
    1
    2
    3
    4
    5
    6
    7
    8
    
    import "slices"
    
    got := []int{0, 1}
    want := []int{0, 9}
    
    if !slices.Equal(got, want) {
          t.Errorf("got %v want %v", got, want)
    } // raise an error
    

Reference

0%