一、切片的定義和使用
package main
import "fmt"
func main() {
//數組定義 var 數組名 [元素個數] 數據類型
//切片定義 var 切片名 [] 數據類型
var s [] int
fmt.Println(s)
}
輸出結果
[]
可以看到,我們在上面的程序中,將切片的定義和數組的定義做了對比,切片的定義時,不需要任何元素個數
當定義完成切片後,我們做打印,發現切片爲空,因沒有任何數據
package main
import "fmt"
func main() {
//數組定義 var 數組名 [元素個數] 數據類型
//切片定義 var 切片名 [] 數據類型
var s [] int
s[0] = 123 //這裏直接給切片複製,會報錯,因爲切片的長度爲零
fmt.Println(s)
}
輸出結果:
panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
D:/go_work/切片.go:9 +0x17
我們定義完切片後,直接通過切片下標進行賦值操作,會出現上述錯誤,因爲這時定義的切片長度爲0,不能直接賦值
我們通過下面的方法,進行切片的定義
package main
import "fmt"
func main() {
//make([] 數據類型, 切片長度)
s := make([] int , 5) //通過自動推導類型,創建一個切片,類型爲int,長度爲5
//通過下標爲切片賦值
s[0] = 123
s[1] = 456
s[2] = 789
fmt.Println(s)
}
二、make方法,創建切片操作,輸出結果:
[123 456 789 0 0]
我們在沒有對切片的元素進行賦值時,該元素的結果爲0,也會被打印。
通過len查看切片長度
//通過len查看切片的長度
fmt.Println(len(s))
結果:
5
是我們定義的長度。
三、切片的擴展:
package main
import "fmt"
func main() {
//make([] 數據類型, 切片長度)
s := make([] int , 5) //通過自動推導類型,創建一個切片,類型爲int,長度爲5
//通過下標爲切片賦值
s[0] = 123
s[1] = 456
s[2] = 789
s[3] = 111
s[4] = 222
//s[5] = 333 //我們不能直接給切片進行,越界賦值,會直接報越界錯誤
//但是通過append,可以直接添加切片元素
s = append(s, 333)
fmt.Println(s)
}
輸出結果:
[123 456 789 111 222 333]
我們可以看到,通過,s[5] = 333 這種方式,不能直接給切片進行擴展操作,如果想要給一個長度已滿的切片進行賦值操作,則需要我們通過append方法,進行添加元素操作。
我們在看看,添加完後的切片長度:
fmt.Println(len(s))
結果爲:6
也可以通過append,添加多個元素,需要在元素值後面用逗號隔開:
s = append(s, 333,444,555)
四、切片的遍歷操作:
1、
package main
import "fmt"
func main() {
//make([] 數據類型, 切片長度)
s := make([] int , 5) //通過自動推導類型,創建一個切片,類型爲int,長度爲5
//通過下標爲切片賦值
s[0] = 123
s[1] = 456
s[2] = 789
s[3] = 111
s[4] = 222
// 切片的遍歷
for i:=0; i<len(s);i++{
fmt.Println(s[i])
}
}
結果:
123
456
789
111
222
通過循環遍歷出切片的值
2、
for i,v:=range s{
fmt.Println(i,v)
}
結果:
0 123
1 456
2 789
3 111
4 222
五、切片初始化操作:
我們在不適用make創建切片的時候,可以直接對切片進行初始化操作。
package main
import "fmt"
func main() {
//這種創建切片的方式,跟創建數組類似
//不寫元素個數的,叫切片,必須寫元素個數的叫數組
//切片與數組都是連續的存儲空間,切片可以擴展,元素不能擴展。
//切片在內存中存儲的區域是堆區。數組的數據存儲在內存中的棧區
var s [] int = []int{1,2,3,4,5}
fmt.Println(s)
}
結果:
[1 2 3 4 5]
六、切片的容量:
package main
import "fmt"
func main() {
var s [] int = []int{1,2,3,4,5}
fmt.Println(s)
//切片的長度
fmt.Println("長度 = ",len(s))
// 切片的容量
fmt.Println("容量 = ", cap(s))
}
結果:
[1 2 3 4 5]
長度 = 5
容量 = 5
可以看到,我們使用cap方法來獲得切片容量大小
我們在s中,添加一個元素
package main
import "fmt"
func main() {
var s [] int = []int{1,2,3,4,5}
fmt.Println(s)
//添加元素:
s = append(s, 6,7,8,9)
//切片的長度
fmt.Println("長度 = ",len(s))
// 切片的容量
fmt.Println("容量 = ", cap(s))
//添加一個元素到s中
s = append(s, 10,11,12,13)
//切片的長度
fmt.Println("長度 = ",len(s))
// 切片的容量
fmt.Println("容量 = ", cap(s))
}
輸出結果:
[1 2 3 4 5]
長度 = 9
容量 = 12
長度 = 13
容量 = 24
可以看到,容量一定是大於等於長度的,且容量的每次擴展是上一次容量的倍數。
當容量大小,超過當前容量,纔會自動擴展。
如果整體數據,沒有超過1024個字節,每次擴展爲上一次的倍數,如果超過1024,則每次擴展是上次的四分之一。
舉例:
package main
import "fmt"
func main() {
s := make([]int, 0 ,1) //容量爲1
oldCap := cap(s)
for i:=0; i<20; i++{
s = append(s,i)
newCap:= cap(s)
if oldCap < newCap{
fmt.Printf("cap: %d========> %d\n", oldCap, newCap)
oldCap = newCap
}
}
}
輸出結果:
cap: 1========> 2
cap: 2========> 4
cap: 4========> 8
cap: 8========> 16
cap: 16========> 32
通過上面這個例子,我們可以看到,是切片的擴容是通過2倍進行的
在看下,下面這個例子:
package main
import "fmt"
func main() {
s := make([]int, 0 ,1) //容量爲1
oldCap := cap(s)
for i:=0; i<200000; i++{ //我們吧循環條件修改變大
s = append(s,i)
newCap:= cap(s)
if oldCap < newCap{
fmt.Printf("cap: %d========> %d\n", oldCap, newCap)
oldCap = newCap
}
}
}
結果:
cap: 512========> 1024 //兩倍擴容
cap: 1024========> 1344 //不再是兩倍擴容
cap: 1344========> 1696
cap: 1696========> 2368
cap: 2368========> 3072
cap: 3072========> 4096
cap: 4096========> 5120
cap: 5120========> 6816
cap: 6816========> 10240
cap: 10240========> 14336
cap: 14336========> 18432
cap: 18432========> 24576
cap: 24576========> 30720
cap: 30720========> 38912
cap: 38912========> 49152
cap: 49152========> 61440
cap: 61440========> 77824
cap: 77824========> 98304
cap: 98304========> 122880
cap: 122880========> 153600
cap: 153600========> 192512
cap: 192512========> 241664
當容量小於1024時是按照2倍容量擴容,當大於等於1024是不是按照2倍容量擴容。
七、切片的截取:
首先說一下切片的截取操作,所謂截取就是從切片中獲取指定的數據。
我們通過如下程序給大家解釋一下:
package main
import "fmt"
func main() {
//定義切片,並完成初始化
s:= []int {10,20,30,40,50}
// 從切片s中截取數據
slice:= s[0:3:5]
fmt.Println(slice)
}
結果:
[10 20 30]
s[0:3:5]是什麼意思呢?
我們可以使用s[low:high:max]來表示
第一個數(low)表示下標的起點(從該位置開始截取),如果low取值爲0表示從第一個元素開始截取,也就是對應的切片s中的10
第二個數(high)表示取到哪結束,也就是下標的終點(不包含該位置),3表示取出下標是0,1,2的數據(10,20,30),不包括下標爲3的數據,那麼也就是說取出的數據長度是3. 可以根據公式:3-0 計算(len=high-low),也就是第二個數減去第一個數,差就是數據長度。在這裏可以將長度理解成取出的數據的個數。
第三個數用來計算容量,所謂容量:是指切片目前可容納的最多元素個數。通過公式5-0計算(cap=max-low),也就是第三個數據減去第一個數。該案例中容量爲5
關於切片的截取還有其它的操作,如下圖所示:
操作 |
含義 |
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) |
通過下面的例子,我們簡單的演示一下:
1、
package main
import "fmt"
func main() {
//定義切片,並完成初始化
s:= []int {0,1,2,3,4,5,6,7,8,9}
// 從切片s中截取數據
slice:= s[:] //不指定容量和長度一樣
fmt.Println("slice = ",slice)
fmt.Printf("len = %d, cap = %d\n", len(slice), cap(slice))
}
輸出結果:
slice = [0 1 2 3 4 5 6 7 8 9]
len = 10, cap = 10
2、
package main
import "fmt"
func main() {
//定義切片,並完成初始化
s:= []int {0,1,2,3,4,5,6,7,8,9}
// 從切片s中截取數據
slice:= s[3:] //從下標3開始
fmt.Println("slice = ",slice)
fmt.Printf("len = %d, cap = %d\n", len(slice), cap(slice))
}
結果:
slice = [3 4 5 6 7 8 9]
len = 7, cap = 7
3、
package main
import "fmt"
func main() {
//定義切片,並完成初始化
s:= []int {0,1,2,3,4,5,6,7,8,9}
// 從切片s中截取數據
slice:= s[:6] //從下0開始,取6個元素,容量是10
fmt.Println("slice = ",slice)
fmt.Printf("len = %d, cap = %d\n", len(slice), cap(slice))
}
結果:
slice = [0 1 2 3 4 5]
len = 6, cap = 10
4、
package main
import "fmt"
func main() {
//定義切片,並完成初始化
s:= []int {0,1,2,3,4,5,6,7,8,9}
// 從切片s中截取數據
slice:= s[2:5] //從下2開始(包含該元素),取到下標5爲止(不包含該元素),切片長度爲3,容量是8,10-2
fmt.Println("slice = ",slice)
fmt.Printf("len = %d, cap = %d\n", len(slice), cap(slice))
}
結果:
slice = [2 3 4]
len = 3, cap = 8
八、copy函數使用
針對切片操作常用的方法除了append( )方法以外,還有copy方法.
基本語法:copy(切片1,切片2)
將第二個切片裏面的元素,拷貝到第一個切片中。
下面通過一個案例,看一下該方法的使用:
package main
import "fmt"
func main() {
s1 := []int{1,2}
s2 := []int{4,5,6,7,8}
copy(s2,s1) //將s1中的元素,拷貝到s2中
fmt.Print(s2)
}
結果:
[1 2 6 7 8]
通過以上結果可以分析出,直接將1切片中兩個元素拷貝到s2元素中相同的位置。而s2原有的元素備替換掉。
在看下面的:
package main
import "fmt"
func main() {
s1 := []int{1,2}
s2 := []int{4,5,6,7,8}
copy(s1,s2) //將s2中的元素,拷貝到s1中
fmt.Print(s1)
}
輸出結果:
[4 5]
而,將s2拷貝到s1,則會吧s1中的元素替換掉。
今天就講到這裏。感謝各位閱讀,歡迎點贊評論。謝謝!!