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