Golang——切片使用大全(创建、初始化、遍历、截取、修改、添加、切片的copy、切片作为函数参数、切片求和、切片求最大值)
概念:
- 切片出現的原因也是因為數組的可操作性不高。切片的長度是不固定的,可以追加數據,可以理解切片是一個動態數組,切片的底層是一個結構體
- 切片類型(slice)本身并不是動態數組或數組指針。它內部通過指針引用底層數組,設定相關屬性將操作限定在指定范圍內。當需要時,會申請更大的內存,將當前數據復制過去, 以實現類似動態數組的功能。
切片的創建:
可直接創建切片對象,無需預先準備數組。因為是引用類型,須使用make函數或顯式初始化語句,它會自動完成底層數組內存分配
普通格式:
var 切片名 [] 數據類型自動推導類型創建切片:
切片名 := [] 類型{}make函數創建切片:
長度是已經初始化的空間,容量是已經開辟的空間,包括已經初始化的空間和空閑的空間
演示:
func main() {s1 := make([]int, 3, 5) // 指定len、cap,底層數組初始化為零值s2 := make([]int, 3) // 省略cap,和len相等s3 := []int{10, 20, 5: 30} // 按初始化元素分配底層數組,并設置len、cap,設置索引5的數據為30fmt.Println(s2, len(s2), cap(s2))fmt.Println(s1, len(s1), cap(s1))fmt.Println(s3, len(s3), cap(s3)) }輸出:
[0 0 0] 3 3 [0 0 0] 3 5 [10 20 0 0 0 30] 6 6切片初始化:
三種創建格式,都是可以通過append向切片添加數據的
初始化格式:
/// 普通格式創建的切片 切片名 [索引] = 值 // 自動推導類型創建的切片 切片名 := [] 類型{數據1,數據2,數據3}// make函數方式創建的切片可以通過append和循環初始化 切片名稱 = append(切片名稱, 數據1,數據2...)演示:
func SliceDemo2() {var slice []intslice = append(slice, 1, 2, 3, 4)slice[1] = 111fmt.Println("切片中的數據", slice)fmt.Println("可以通過索引取部分數據", slice[0])fmt.Println("切片長度:", len(slice)) }func SliceDemo03() {slice := []int{1, 2, 3, 4, 5}slice = append(slice, 6, 7, 8, 9, 10)slice[1] = 111fmt.Println("切片中的數據", slice)fmt.Println("可以通過索引取部分數據", slice[0])fmt.Println("切片長度:", len(slice)) }func SliceDemo04() {slice := make([]int, 3, 4)for i := 0; i < len(slice); i++ {slice[i] = i + 1}slice = append(slice, 1)fmt.Println("切片中的數據", slice)fmt.Println("可以通過索引取部分數據", slice[0])fmt.Println("切片長度:", len(slice))fmt.Println("切片容量:", cap(slice)) }注意下面兩種定義方式的區別。前者僅定義了一個[ ]int類型變量,并未執行初始化操作, 而后者則用初始化表達式完成了全部創建過程
func main() {var a []intb := []int{}println(a == nil, b == nil) }可獲取元素地址,但不能向數組那樣直接通過指針(*slice)訪問元素內容
func main() {s := []int{0, 1, 2, 3, 4}p := &s // 取s地址p0 := &s[0] // 取s[0]地址p1 := &s[1]println(p, p0, p1)// 取p中[1]的數據且加100(*p)[1] += 100 // *[]int不支持indexing操作,須先用指針操作符獲取[]int對象fmt.Println(s)fmt.Println((*p)[1]) //這里加括號是優先級問題 }如果元素類型也是切片,那么就能實現類似交錯數組的功能
func main() {x := [][]int{{1, 2},{10, 20, 30},{100},}fmt.Println(x[1])x[2] = append(x[2], 200, 300)fmt.Println(x[2]) }輸出:
[1 2] [10 20 30] [100]切片遍歷:
遍歷和數組一樣可以使用普通的for循環和range遍歷得到
演示:
func main() {slice := []int{1, 2, 3, 4, 5}for i := 0; i < len(slice); i++ {fmt.Print(slice[i])}for _, v := range slice {fmt.Println(v)} }切片截取:
切片截取就是從切片中獲取指定的數據
如果初始化切片時,沒有指定切片的容量,切片容量是跟隨原切片的
切片截取的操作:
| s[n] | 切片s中索引位置為n的項 |
| s[:] | 從切片s的索引位置0到len(s)-1處所獲得的切片 |
| s[low:] | 從切片s的索引位置low到len(s)-1處所獲得的切片 |
| s[:high] | 從切片s的索引位置0到high處所獲得的切片,len=high |
| s[low:high] | 從切片s的索引位置low到high處所獲得的切片,len=high-low |
| s[low:high:max] | 從切片s的索引位置low到high處所獲得的切片,len=high-low,cap=max-low |
| len(s) | 切片s的長度,總是<=cap(s) |
| cap(s) | 切片s的容量,總是>=len(s) |
切片值的修改:
切片截取后返回新切片,對新切片的值進行修改,會影響原來的切片
原因:
切片截取后新的切片,不會給新的切片是指向了原來的切片,沒有給新的切片開辟新的空間,所以對于新的切片操作會影響到原來的切片
演示:
func main() {slice := []int{1, 2, 3, 4, 5}newSlice2 := slice[0:3]fmt.Println("切片修改前slice的數據:", slice)newSlice2[0] = 1111fmt.Println("切片修改后slice的數據:", slice) }輸出:
切片修改前slice的數據: [1 2 3 4 5] 切片修改后slice的數據: [1111 2 3 4 5]append函數:
append函數是向切片的末尾slice(len)添加數據
如果添加的內容超出了切片初始定義的容量,切片會自動擴容
擴容機制是:上一次的容量 * 2
如果超過1024字節,每次擴容上一次的1/4
append每次擴容都是一個新的內存,和原來的無關聯,所以如果是通過參數傳遞的方式,使用append添加數據,但是不會影響到原切片的數據,原因就是append每次拓展都是一個新的空間,指向的內存不再是原切片。
輸出:
初始切片的數據: [0 0 0] 長度: 3 第一次添加數據: [0 0 0 1] 長度: 4 第二次添加數據: [0 0 0 1 2 3 4 5 6 7 8 9] 長度: 12copy函數:
把切片2的數據(0索引到len-1)賦值到切片1中
注意:如果切片1的容量不夠,則不賦值剩余的數據。如果切片1的數據比切片2的多,從切片2復制的數據是有多少,復制多少。
總結:copy只是復制索引相對應的數據,如果長度不夠,不會覆蓋原來的數據
格式:
copy(切片1,切片2)演示:
// 從切片2復制到切片1,但是切片2的數據比切片1的多,所以,最終只是復制了一部分,也就是索引相對應的數據 func main() {slice := []int{1, 2, 3}slice2 := []int{4, 5, 6, 7, 8, 9}copy(slice, slice2)fmt.Println(slice) // [4 5 6] }// 從切片1復制到切片1,但是切片1的數據比切片2的少,所以,最終只是復制了一部分,也就是索引相對應的數據 func main() {slice := []int{1, 2, 3}slice2 := []int{4, 5, 6, 7, 8, 9}copy(slice2, slice)fmt.Println(slice2) // [1 2 3 7 8 9] }還可直接從字符串中復制數據到[ ]byte
func main() {b := make([]byte, 3)n := copy(b, "abcde")fmt.Println(n, b) }切片作為函數參數:
切片可以做為函數的參數,但是在函數中修改切片的值,會影響到原切片
因為切片的底層是結構體,結構體里有個參數Pointer,Pointer會指向切片的內存地址,使用的是淺拷貝方式,所以會影響到原切片值
演示:
func main() {slice := []int{1, 2, 3, 4, 5}SliceDemo10(slice) }func SliceDemo10(slice []int) {for _, v := range slice {fmt.Println(v)}slice = append(slice, 5, 6, 7)fmt.Println(slice) }輸出:
1 2 3 4 5 [1 2 3 4 5 5 6 7]切片求和:
func main() {// 定義變量,并收集用戶輸入的個數var count intfmt.Println("請輸入要求和的個數:")fmt.Scan(&count)// 定義切片,將輸入的個數保存到切片slice := make([]int, count)statisticalData(slice)// 求和summation(slice) }func statisticalData(slice []int) {for i := 0; i < len(slice); i++ {fmt.Printf("請輸入第%d個數\n", i+1)fmt.Scan(&slice[i])} } func summation(slice []int) {var sum intfor i := 0; i < len(slice); i++ {sum += slice[i]}fmt.Println("和為:", sum) }切片求最大值:
func main() {// 定義變量,并收集用戶輸入的個數var count intfmt.Println("請輸入要比較的數:")fmt.Scan(&count)// 定義切片,將輸入的個數保存到切片slice := make([]int, count)statisticalData(slice)// 比較最大值maximum(slice) }func statisticalData(slice []int) {for i := 0; i < len(slice); i++ {fmt.Printf("請輸入第%d個數\n", i+1)fmt.Scan(&slice[i])} }func maximum(slice []int) {max := slice[0]for i := 0; i < len(slice); i++ {if max < slice[i] {max = slice[i]}}fmt.Println("最大值是:", max) }總結
以上是生活随笔為你收集整理的Golang——切片使用大全(创建、初始化、遍历、截取、修改、添加、切片的copy、切片作为函数参数、切片求和、切片求最大值)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java手游 《剑心》_java
- 下一篇: Spring AOP切入点与通知XML类