---
# System prepended metadata

title: 'Day 11 : Golang Slice (2)'
tags: [About Go]

---

# Day 11 : Golang Slice (2)
## 前言
在第一篇slice的文章，slice本身是不會儲存任何值，而是透過指針指向底下的陣列，代表這個slice是要從陣列哪個index開始，並記錄slice自己的長度(len)與容量(cap)，且如果要更改slice裡面的元素，其實是修改底下隱藏的陣列。

這時可以想到，之前提到陣列是有固定長度，不能新增或修改，而slice是可以隨時新增刪除，那麼當我們一值新增slice元素時，其大小會超過底下的隱藏陣列(len>cap)時會怎麼辦呢? 這時候Go會在底層建立一個更大的陣列，將舊陣列的內容複製到新陣列，在把slice的指標指向這個新陣列。

## 實際練習
接下來用append和copy來學習是否有新增陣列的差異。
1. 單純新增slice，指向同一個底層的陣列。
s2是直接複製slice，所以是會產生一個新的slice，指向和s1一樣的底層array(將s1儲存的位置給s2)
s3建立一個新的slice，範圍是s1的第一個元素到最後一個元素，指向同一個陣列
```go=
func main() {
	a1, a2, a3 := linked()
	fmt.Println(a1) // 99
	fmt.Println(a2) // 99
	fmt.Println(a3) // 99
}

func linked() (int, int, int) {
	s1 := []int{1, 2, 3, 4, 5}
	s2 := s1 
	s3 := s1[:] 
	fmt.Printf("s1 底層的陣列的記憶體位置：%p\n", &s1[0])  // 0xc00000e420
	fmt.Printf("s2 底層的陣列的記憶體位置：%p\n", &s2[0])  // 0xc00000e420
	fmt.Printf("s3 底層的陣列的記憶體位置：%p\n", &s3[0])  // 0xc00000e420
	s2[3] = 99
	return s1[3], s2[3], s3[3]
}
```
2. 新增元素，會超過原本slice的容量，會創造新的陣列
當在第12行append新值的時候，會超過原本s1的容量，創造新的底層陣列，並將s1指向新的底層陣列。故之後透過`s1[2]=99`修改元素後，s2因為指向原本的底層陣列，所以值不會變，s1會指向新的底層陣列，所以s1[2]是99。
```go=
func main() {
    b1, b2 := noLink()
    fmt.Println("b1",b1)  // 99 
    fmt.Println("b2",b2)  // 3
}

func noLink() (int, int) {
    s1 := []int{1, 2, 3, 4, 5}   // len : 5 cap : 5
    s2 := s1
    fmt.Printf("s1: %p\n", &s1[0]) // s1 : 0xc00000e420
    fmt.Printf("s2: %p\n", &s2[0]) // s2 : 0xc00000e420
    s1 = append(s1, 6)
    fmt.Printf("s1: %p\n", &s1[0]) // s1 : 0xc000010280 
    fmt.Printf("s2: %p\n", &s2[0]) // s2 : 0xc00000e420
    s1[2] = 99
    return s1[2], s2[2]
}
```
![](https://i.imgur.com/HAJj67J.png)
(圖一，自行繪製)

3 `copy(<目標的slice>,<來源的slice>)`。透過copy將s1裡面的元素複製到s2中，因為s1和s2是指向不同底層的陣列，所以單純對s1的修改不會影響到s2。
```go=
func main() {
    c1, c2, c3 := copyFunc()
    fmt.Println("c1", c1) // 99
    fmt.Println("c2", c2) // 4
    fmt.Println("c3", c3) // 5, 代表複製了5個變數
}
func copyFunc() (int, int, int) {
    s1 := []int{1, 2, 3, 4, 5}
    s2 := make([]int, 5)
    fmt.Printf("s1: %p\n", &s1[0]) // 0xc00000e420
    fmt.Printf("s2: %p\n", &s2[0]) // 0xc00000e450
    copied := copy(s2, s1)
    fmt.Printf("s1: %p\n", &s1[0]) // 0xc00000e420
    fmt.Printf("s2: %p\n", &s2[0]) // 0xc00000e450
    s1[3] = 99
    return s1[3], s2[3], copied
}
```



## References
1. [良葛格-底層為陣列的 slice](https://openhome.cc/Gossip/Go/Slice.html)


###### tags: `About Go`