---
# System prepended metadata

title: '[Golang] 初見Golang - 常見資料結構篇'
tags: [Golang]

---

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