數(shù)組類型的值(以下簡(jiǎn)稱數(shù)組)的長(zhǎng)度是固定的伶棒,而切片類型的值(以下簡(jiǎn)稱切片)是可變長(zhǎng)的吊趾。
?數(shù)組的長(zhǎng)度在聲明它的時(shí)候就必須給定,并且在之后不會(huì)再改變穆碎。可以說,數(shù)組的長(zhǎng)度是其類型的一部分宛渐。
golang數(shù)組的四種聲明方法
第一種
// var <數(shù)組名稱> [<數(shù)組長(zhǎng)度>]<數(shù)組元素>
var arra [2]int
arr[0]=1
arrp1[=2
第二種
// var <數(shù)組名稱> = [<數(shù)組長(zhǎng)度>]<數(shù)組元素>{元素1屁奏,元素2,...}
var arr = [2]int{1,2}
//或者
arr := [2]int{1,2}
第三種
// var <數(shù)組名稱>[<數(shù)組長(zhǎng)度>]<數(shù)組元素>=[...]<元素類型>{元素1色徘,元素2恭金,...}
var arr =[...]int{1,2}
//或者
arr :=[...]int {1,2}
第四種
// var <數(shù)組名稱>[<數(shù)組長(zhǎng)度>]<數(shù)組元素>=[...]<元素類型>{索引1:元素1,索引2:元素2,...}
var arr = [...]int{1:1,0:2}
// 或者
arr := [...]int{1:1,0:2}
?切片的長(zhǎng)度可以自動(dòng)地隨著其中元素?cái)?shù)量的增長(zhǎng)而增長(zhǎng)褂策,但不會(huì)隨著元素?cái)?shù)量的減少而減少横腿。
golang切片的3種聲明方法
①定義一個(gè)切片,然后讓切片去引用一個(gè)已經(jīng)創(chuàng)建好的數(shù)組
var arr [5]int = [...]int{1,2,3,4,5}
var slice = arr [1:3]
②通過make來創(chuàng)建切片
// var 切片名 []type = make([], len, [cap])辙培;參數(shù)說明:type是數(shù)據(jù)類型蔑水、len是大小、cap是切片容量(容量必須>=長(zhǎng)度)
通過make方式創(chuàng)建切片可以指定切片大小和容量
如果沒有給切片的各個(gè)元素賦值扬蕊,那么就會(huì)使用默認(rèn)值(int搀别、float=>0, strint=>"", bool=>false)
榮國(guó)make方式創(chuàng)建的切片對(duì)應(yīng)的數(shù)組是由make底層維護(hù),對(duì)外不可見尾抑,也就是只能通過slice訪問各個(gè)元素
var slice []float64 = make([]float64, 5, 10)
③定義一個(gè)切片歇父,直接就指定具體數(shù)組,使用原理類似于make的方式
var slice []string = []string{"zhangsan", "lisi", "wangwu"}
?我們其實(shí)可以把切片看做是對(duì)數(shù)組的一層簡(jiǎn)單的封裝再愈,因?yàn)樵诿總€(gè)切片的底層數(shù)據(jù)結(jié)構(gòu)中榜苫,一定會(huì)包含一個(gè)數(shù)組。后者可以被叫做前者的底層數(shù)組翎冲,而前者也可以被看作是對(duì)后者的某個(gè)連續(xù)片段的引用垂睬。
?也正因?yàn)槿绱耍珿o語(yǔ)言的切片類型屬于引用類型抗悍,同屬引用類型的還有后面會(huì)講到的字典類型驹饺、通道類型、函數(shù)類型等缴渊;而Go語(yǔ)言的數(shù)組類型則屬于值類型赏壹,同屬值類型的有基礎(chǔ)數(shù)據(jù)類型以及結(jié)構(gòu)體類型。
?注意衔沼,Go語(yǔ)言里不存在像java等編程語(yǔ)言中那種令人困惑的“傳值或傳引用”問題蝌借。在Go語(yǔ)言中昔瞧,我們判斷所謂的“傳值”或者“傳引用”只要看北傳遞的值的類型就好了。如果傳遞的值是引用類型的菩佑,那么就是“傳引用”自晰。如果傳遞的值是值類型的,那么就是“傳值”擎鸠。從傳遞成本的角度講缀磕,引用類型的值往往要比值類型的值低很多。
怎樣正確估算切片的長(zhǎng)度和容量劣光?
package main
import "fmt"
func main(){
// 示例1
s1 :=make([]int,5)
fmt.println("The length of s1: %d\n",len(s1))
fmt.println("The capacity of s1:%d\n",cap(s1))
fmt.println("The value of s1: %d\n",s1)
s2 := make([]int,5,8)
fmt.println("The length of s2:%d\n",len(s2))
fmt.println("The capacity of s2:%d\n",cap(s2))
fmt.println("The value of s2: %d\n",s2)
}
首先袜蚕,內(nèi)建函數(shù)make聲明了一個(gè)[]int類型的變量s1。我傳給make函數(shù)的第二個(gè)參數(shù)是5绢涡,從而指明了該切片的長(zhǎng)度牲剃。再用幾乎相同的方式聲明了切片s2,只不過多傳了一個(gè)參數(shù)8以指明該切片的容量雄可。
切片s1和s2的容量分別是5和8凿傅。
原因:當(dāng)我們用make函數(shù)初始化切片時(shí),如果不指名其容量数苫,那么它就會(huì)和長(zhǎng)度一致聪舒。如果在初始化時(shí)指明了容量,那么切片的實(shí)際容量也就是它了虐急。這也正是s2的容量是8的原因箱残。
s3: = []int{1,2,3,4,5,6,7,8}
s4 := s3[3:6]
s4的長(zhǎng)度為3,容量為5
原因:由于s4是通過在s3上施加切片操作得來的止吁,所以s3的底層數(shù)組就是s4的底層數(shù)組被辑。又因?yàn)椋诘讓訑?shù)組不變的情況下敬惦,切片代表的窗口可以向右擴(kuò)展盼理,直至其底層數(shù)組的末尾。所以俄删,s4的容量就是其底層數(shù)組的長(zhǎng)度8減去上述切片表達(dá)式中的那個(gè)起始索引3宏怔,即5。
注意:切片帶邊的窗口是無法向左擴(kuò)展的也就是說畴椰,我們永遠(yuǎn)無法透過s4看到s4左邊的那3個(gè)元素臊诊。
最后,隨便提一下把切片的窗口向右擴(kuò)展到最大的方法迅矛。對(duì)于s4來說,切片表達(dá)式s4[0:cap(s4)]就可以做到潜叛。該表達(dá)式的結(jié)果(即一個(gè)新的切片)會(huì)是[]int{4,5,6,7,8}秽褒,其長(zhǎng)度和容量都是5壶硅。
知識(shí)擴(kuò)展
1.切片如何擴(kuò)容?
一旦一個(gè)切片無法容納更多的元素销斟,Go于洋就會(huì)想辦法擴(kuò)容庐椒。但它并不會(huì)改變?cè)瓉淼那衅巧梢粋€(gè)容量更大的切片蚂踊,然后將把原有元素和新元素一并拷貝到新切片中约谈。
在一般的情況下,你可以簡(jiǎn)單地認(rèn)為新切片的容量將是原切片容量的2倍犁钟。
但是棱诱,當(dāng)原切片的長(zhǎng)度大于或等于1024時(shí),Go語(yǔ)言會(huì)將以原容量的1.25倍作為新容量的基準(zhǔn)涝动。
新容量基準(zhǔn)會(huì)被調(diào)整(不斷與1.25相乘)迈勋,直到結(jié)果不小于原長(zhǎng)度與要追加的元素?cái)?shù)量之和(以下簡(jiǎn)稱新長(zhǎng)度)。最終醋粟,新容量往往會(huì)比新長(zhǎng)度要大一些靡菇,當(dāng)然,相等也是可能得米愿。
2.切片的底層數(shù)組什么時(shí)候會(huì)被替換厦凤?
確切地說,一個(gè)切片的底層數(shù)組永遠(yuǎn)不會(huì)被替換育苟。雖然在擴(kuò)容的時(shí)候Go語(yǔ)言一定會(huì)生成新的底層數(shù)組较鼓,但是它同時(shí)生成了新的切片。它是把新的切片作為了新底層數(shù)組的窗口宙搬,而沒有對(duì)原切片及其底層數(shù)組做任何改動(dòng)笨腥。
在無須擴(kuò)容時(shí),append函數(shù)返回的是指向原底層數(shù)組的切片勇垛,而在需要擴(kuò)容時(shí)脖母,append函數(shù)返回的是指向新底層數(shù)組的新切片。
所以闲孤,嚴(yán)格來說谆级,“擴(kuò)容”這個(gè)詞用來這里雖然形象但并不適合。
順便說一下讼积,只要新長(zhǎng)度不會(huì)超過切片的原容量肥照,那么使用append函數(shù)對(duì)其追加元素的時(shí)候就不會(huì)引起擴(kuò)容。這只會(huì)使緊鄰切片窗口右邊的(底層數(shù)組中的)元素被替換成新的元素勤众。