# [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)