# 定義 切片是由陣列建立的一種方便、靈活且功能強大的包裝(Wrapper)。切片本身不擁有任何資料。它們只是對現有陣列的引用 陣列定長,長度不能改變---》python中列表----》go切片 # 知識點 1 建立一個切片(透過陣列建立) 2 使用 make 建立一個切片 3 切片的修改 4 切片的長度和容量 5 追加切片元素 6 切片的函式傳遞 7 多維切片 8 記憶體最佳化 —————————————————————————————————— package main import "fmt" // 切片 func main() { // 1 建立一個切片(透過陣列建立) var a [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} // 切片--->從a陣列上,從0到結尾,切片賦值給s //var s = a[:] var s []int = a[:] fmt.Println(s) // 檢視型別--->中括號中沒有數字-->就是切片,有數字就是陣列 // 區分陣列(值)和切片(引用)型別 fmt.Printf("s的型別是:%T\n", s) // []int // 2 使用 make 建立一個切片-->必須透過make或透過陣列切出來,否則是空的 var s1 []string = make([]string, 4) fmt.Println(s1) // 3 切片零值 // 3.1 透過陣列切出來,不會為 空 // 3.2 如果只定義,沒有初始化--》零值---》空---》nil var s2 []string fmt.Println(s2) // [] // 4 操作切片---》取值,賦值---》使用 [數字] s1[0] = "lqz" s1[1] = "彭于晏" fmt.Println(s1) s1[0] = "ssdfasdf" fmt.Println(s1) // 5 如果切片為 空,nil--》沒有初始化 不能使用(取值賦值) s2 = make([]string, 1) // 不是nil了,但是長度為0 if s2 == nil { // python 的None fmt.Println("s2不能初始化,不能使用") return } s2[0] = "lqz" // s2沒有初始化,報錯 index out of range [0] with length 0 fmt.Println(s2) // 使用切片 s1[0]---》報index out of range [0] with length 0--》兩個原因:1 nil 2 長度不夠 // 6 切片的長度和容量 // 長度:切片放了幾個值 // 容量:切片總共能放幾個值 var a1 [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var s3 []int = a1[2:3] fmt.Println(s3) // [6 7] 前閉後開區間 fmt.Println(len(s3)) // len 長度 2 fmt.Println(cap(s3)) // cap 容量 5 切片基於底層陣列,容量取決於底層陣列--》從切片起始位置到陣列最後 var s4 = make([]int, 2, 4) fmt.Println(len(s4)) // 2 fmt.Println(cap(s4)) // 4 // 7 追加切片元素 // s4 長度是2,容量是4,還能追加倆值 s4 = append(s4, 99) // 內建函式追加--->s4不是物件 fmt.Println(s4) fmt.Println(len(s4)) // 3 fmt.Println(cap(s4)) // 4 s4 = append(s4, 88) // 內建函式追加--->s4不是物件 fmt.Println(s4) fmt.Println(len(s4)) // 4 fmt.Println(cap(s4)) // 4 // 超過容量,再追加---》不會報錯---》 s4 = append(s4, 77) // 內建函式追加--->s4不是物件 fmt.Println(s4) fmt.Println(len(s4)) // 5 fmt.Println(cap(s4)) // 8---》翻倍擴容 s4 = append(s4, 66, 55, 44, 33) // fmt.Println(s4) fmt.Println(len(s4)) // 9 fmt.Println(cap(s4)) // 16---》翻倍擴容 s4 = append(s4, 22, 11, 12, 13, 11, 12) // fmt.Println(s4) fmt.Println(len(s4)) // 16 fmt.Println(cap(s4)) // 16---》翻倍擴容-->32 //8 切片的函式傳遞 切片是引用型別 test001(s4) // [0 0 99 88 77 66 55 44 33 22 11 12 13 11 12 13] fmt.Println("外部:", s4) // 函式內修改,會影響原來的值 // 很深的坑: s4 長度和容量 都是16 當引數傳到函式中,修改,會不會影響原來的? test002(s4) fmt.Println("外部:", s4) // 函式內修改,會影響原來的值 /* 1 因為切片依賴於底層陣列 2 底層陣列的改變會影響切片,切片的改變也會影響底層陣列 3 當使用append追加上,如果超過了切片容量--》切片會擴容--》重新建立一個陣列--》把原來的值複製過去--》容量翻倍了--》切片指向新的陣列 4 如果當引數傳遞,再函式中,使用append 1 超過容量,只要超過後,再修改某個位置的值,就不會相互影響了 2 如果沒有超過容量,再修改某個位置的值,會相互影響了 */ // 9 多維切片 var s5 [][]int = make([][]int, 2, 3) //s5[0]=1 s5[0] = make([]int, 3) // 內層切片使用,也要初始化 s5[0][0] = 99 // 報錯了---》內層的切片,沒有透過make初始化出來,不能用 fmt.Println(s5) var s6 [][3]int = make([][3]int, 2, 3) fmt.Println(s6[0]) s6[0][0] = 99 fmt.Println(s6) // 多維切片,第n層,要不要初始化,取決於第n層是什麼型別 // 定義並賦初值 var s7 [][]string = [][]string{{"lqz", "小紅"}, {"asfd"}, {"111", "22", "333", "444"}} //var s7 [][4]string = [][4]string{{"lqz", "小紅"}, {"asfd"}, {"111", "22", "333", "444"}} fmt.Println(s7[0][1]) fmt.Println(len(s7[2])) // 1 fmt.Println(cap(s7[2])) // 1 //fmt.Println(s7[2][4]) // 越界了 //fmt.Println(s7[0][2]) // 陣列不會越界,切片就會越界 s7[0] = append(s7[0], "中") fmt.Println(len(s7[0])) // 3 fmt.Println(cap(s7[0])) // 4 // 10 記憶體最佳化 copy函式 var a3 [100]int fmt.Println(a3) var s8 []int = a3[0:3] fmt.Println(s8) s8[0] = 88 fmt.Println(s8) fmt.Println(a3) a3[1] = 66 fmt.Println(s8) fmt.Println(a3) //s8 複製到小一點的切片上(底層陣列小) ---》可以大可以小 var s9 = make([]int, 5, 5) copy(s9, s8) fmt.Println(s9) // 長度和容量,都是3--》以後操作s9-->傳參,修改---》底層陣列只有3的大小---》記憶體空間佔用小 } func test001(s []int) { s[0] = 999 fmt.Println(s) } func test002(s []int) { s[0] = 999 fmt.Println(s) // 如果,再內部,append--——》追加--》超過容量--》放棄掉底層陣列---》新建立一個新陣列--》指向新陣列 s = append(s, 666) fmt.Println("內部", s) s[0] = 888 fmt.Println("內部", s) }
package main import "fmt" // 可變長引數 func main() { // * ** 放在形參上 // *:接收任意長度的位置引數 // ** 接收任意長度的關鍵字引數 // * ** 放在實參上--》* 只能放在列表上, ** 只能放在字典上 // go 只有按位置傳引數---》沒有按關鍵字這種用法 test003(33, 44, "9") // 傳任意長度引數 //fmt.Println(1,2,3,4,5,"dafas") test004("11", "22", "14", "15", "16", "17", "18", "19") var ss1 [5]string = [5]string{"lqz", "彭于晏", "劉亦菲"} test004(ss1[:]...) // 打散了傳入 // 思考題 welcome := []string{"hello", "world"} // 長度是2,容量是2 //welcome := make([]string,3,4) // change(welcome...) // 內部本質就是把 welcome 給了 s fmt.Println(welcome) // {"Go", "world"} } func test003(a, b int, c string) { fmt.Println(a, b, c) } func test004(a ...string) { fmt.Println(a) // 可以傳任意長度字串===>a是什麼型別?字串型別? 字串切片型別 []string fmt.Printf("a的型別是:%T", a) //for i := 0; i < len(a); i++ { // fmt.Println(a[i]) //} for _, value := range a { fmt.Println(value) } } func change(s ...string) { s[0] = "Go" s = append(s, "playground") fmt.Println(s) // [Go world playground] s[0] = "lqz" fmt.Println(s) // [lqz world playground] }
# 陣列,切片,map 容器型別
# map 是在 Go 中將值(value)與鍵(key)關聯的內建型別。透過相應的鍵可以獲取到值
如何建立 map
給 map 新增元素
獲取 map 中的元素
刪除 map 中的元素
獲取 map 的長度
Map 是引用型別
Map 的相等性
# python中的字典 # go中得map # redis中得 hash # java中得 HashMap,TreeMap # 1 就是根據key即經過一個函式f(key)得到的結果的作為地址去存放當前的key value鍵值對(這個是hashmap的存值方式),但是卻發現算出來的地址上已經有人先來了 就是相當於你在蹲坑,又有人進來了,但是隻有一個坑,就產生了衝突,需要開闢新的空間去讓另一個人有地方上廁所 # 2 解決hash衝突 1 開放定址法 1.1 線性探測 按順序決定值時,如果某資料的值已經存在,則在原來值的基礎上往後加一個單位,直至不發生雜湊衝突。 就是在此空間不足時,直接放入此空間的後一個空的空間 1.2 偽隨機探測 2 再雜湊法(Rehashing): 使用另一個雜湊函式處理衝突 3 鏈地址法(java的hashmap): - 對於相同的值,使用連結串列進行連線。使用陣列儲存每一個連結串列 4 建立公共溢位區