# 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`