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