# [Golang] 初見Golang - 常見資料結構篇 ###### tags: `Golang` ## Array 陣列,我們都很熟悉,「是一區塊同類型且固定大小的記憶體」,以下是陣列在`Golang`中的使用方式(語法): ```go= // 宣告 arr1 := [5]int{1, 2, 3, 4, 5} // #1 arr2 := [5]int{1} // #2 arr3 := [...]int{1, 2, 3, 4, 5} // #3 arr4 := [5]int{2:1, 3:2, 4:3} // #4 arr5 := [...]int{2:1, 4:5} // #5 // 陣列大小 arr1_len := len(arr1) fmt.Println("array 1 length: ", arr1_len) // output: array 1 length: 5 // 對陣列進行簡單的迴圈處理 for i := 0; i < len(arr1); i++ { arr1[i] += 1 fmt.Printf("[%d]: %d, ", i, arr1[i]) } // output: [0]: 2, [1]: 3, [2]: 4, [3]: 5, [4]: 6, ``` ### 宣告方式 ==請對照上面的範例,後面註解的數字對應以下宣告方式== 1. 最基本的方法,陣列裡有**5**個元素,依序為`1, 2, 3, 4, ,5` 2. 陣列初始大小為**5**,依序為`1, 0, 0, 0, 0`,並不是將**5**個元素全部初始化為`1` 3. 陣列元素依序為`1, 2, 3, 4, 5`,長度由初始化的元素數量決定 4. 陣列初始大小為**5**,陣列元素依序為`0, 0, 1, 2, 3` 5. 陣列元素依序為`0, 0, 1, 0, 5`,長度由初始化的元素數量決定 ## Map `Map`,中文翻作映射,也是一個常用的資料結構,用法與`C++ STL`裡的`std::map`和`std::unordered_map`以及`C#`裡的`Dictionary<TK, TV>`一樣。 :::success :book: `Golang`裡的`Map`的底層實作為雜湊表(Hash table) - [來源](https://github.com/golang/go/blob/master/src/runtime/map.go#L9) ::: 以下是基本使用方式: ```go= // 宣告 users := make(map[string]string) // [key: string, value: string] // 加入資料 users["7458"] = "Charlie" users["6422"] = "POKA" users["9738"] = "Wendy" users["7458"] = "York" if users["7458"] == "Charlie" { fmt.Println("KO NO Charlie DA!") } else if users["7458"] == "York" { fmt.Println("KO NO York DA!") } // 檢查資料是否存在(利用key) val, ok := users["6233"] if !ok { fmt.Println("Value does not exit.") } else { fmt.Println("Value is ", val) } // 假如你只是要檢查值在不在,不需要值的結果 _, ok = users["6233"] // 注意不是":=",是"=" // Map的大小,與陣列的用法一樣 users_sz := len(users) fmt.Println("Count of users: ", users_sz) // 刪除資料 delete(users, "6422") _, ok = users["6422"] if !ok { fmt.Println("POKA has been killed") } ``` ## Slice 切片(`Slice`)使用起來與`C#`中的`List<T>`和`C++`中的`std::vector<T>`一樣,直覺上就是動態陣列,但請注意,切片在**底層是存儲位址(reference)**,類似`C#`的`List`,所以它是一塊存儲 額外提一下,`C++`的`std::vector<T>`是複製資料(value type)。 使用方法: ```go= // 宣告 s1 := []int{1, 2, 3, 4, 5} // #1 s2 := make([]int, 5) // #2 s3 := make([]int, 5, 10) // #3 // 由陣列初始化 arr := [5]int{1, 2, 3, 4, 5} s4 := arr[:] // #4 s5 := arr[1:3] // #5 s6 := arr[1:] // #6 s7 := arr[:3] // #7 s8 := s4[:] // #8 s9 := []int{} // #9 // 加入資料 s1 = append(s1, 4, 5, 6, 7, 8) for i := 0; i < len(s1); i++ { fmt.Printf("%d "s1[i]) } // output: 1 2 3 4 5 4 5 6 7 8 ``` ### 宣告方式 ==請對照上面的範例,後面註解的數字對應以下宣告方式== - `#1`看起來是陣列,但事實上是切片 - `#2`、`#3`是利用`make`函式初始化,`#2`表示動態配置一切片,長度**5**,`#3`差別在當前長度為**5**,並且預留**10**個`int`空間 - `#4`到`#8`利用已有的陣列進行初始化,`#4`表示取整個`arr`為初始,**`#5`方括號內的表示取陣列`[start_index: end_index - 1]`** - `#9`是合法的,初始化長度為`0`沒有值的切片(會預留`4`個空間) ### 刪除 `slice`要進行刪除並沒有像`Map`一樣有`delete`這樣的函式,但可以用`append()`進行刪除,如下: ```go= slice := []int {1, 2, 3, 4, 5, 6, 7, 8} // 刪除第三個元素 slice = append(slice[:3], slice[4:]...) ``` ## 迭代(Iterate)與`range`關鍵字 對於這些集合最常見的操作是對他做遍歷,`Golang`提供了關鍵字`range`對這些集合進行迭代 ```go= // Array & Slice arr := [5]int{1, 2, 3, 4, 5} for index, value := range arr { fmt.Printf("[%d]: %d\n", index, value) } // Map users := make(map[string]string) users["7458"] = "Charlie" users["6422"] = "POKA" users["9738"] = "Wendy" for key, val := range users { fmt.Printf("[%s]: %s\n", key, val) } ``` ## 來源資料 - [使用陣列 (Array) 和切片 (Slice)](https://michaelchen.tech/golang-programming/array-slice/) - [使用映射 (Map)](https://michaelchen.tech/golang-programming/map/) - [Arrays vs Slices](https://www.godesignpatterns.com/2014/05/arrays-vs-slices.html)