golang中數(shù)組和切片到底有什么區(qū)別?
數(shù)組大家都知道是具有「固定長(zhǎng)度及類型的序列集合」,但是golang中又引入了「切片」,語(yǔ)法上看起來(lái)還和數(shù)組差不多,為什么會(huì)引入這些呢?切片和數(shù)組到底有什么區(qū)別呢?接下來(lái)咱們來(lái)一個(gè)一個(gè)的看。
數(shù)組 array
定義數(shù)組
上述語(yǔ)句表示的意思是,我們來(lái)定義一個(gè)變量arr 為5個(gè)長(zhǎng)度的int的數(shù)組類型,也就是[5]int,同時(shí)給賦值上了初始值 1、2、3、4、5,內(nèi)存分布如圖

緊密挨在一起的數(shù)據(jù)結(jié)構(gòu)集合
注意
如果定義數(shù)組的方法是;
那么arr的數(shù)據(jù)類型為*[4]int,而不是[4]int;
不定長(zhǎng)數(shù)組
當(dāng)然數(shù)組的長(zhǎng)度4如果是不固定的,可以用...的方式代替
數(shù)組的循環(huán)
數(shù)組的循環(huán)在golang中有一個(gè)特有的語(yǔ)法,就是 for range
數(shù)組的常用方法
常用方法是「len()」 方法和 「cap()」 方法;
- len()方法的作用是獲取數(shù)組或者切片的「長(zhǎng)度」
- cap()方法的作用是獲取數(shù)組或者切片的「容量」
但是「在數(shù)組中,這兩個(gè)值永遠(yuǎn)相同」,所以在這里咱們不多做考慮,在后面切片中再詳細(xì)闡述。
切片 slice
為什么會(huì)有切片?
切片之所以會(huì)誕生,是因?yàn)間olang中數(shù)組存在很大的兩個(gè)問(wèn)題
固定的長(zhǎng)度,這意味著初始化 array 后,不能再 push 超過(guò) len(array) 長(zhǎng)度的元素
array 作為參數(shù)在函數(shù)之間傳遞時(shí)是值傳遞,相當(dāng)于把數(shù)據(jù)copy了一份,具有很大的性能浪費(fèi)
切片數(shù)據(jù)類型的底層結(jié)構(gòu)
比如我們定義了一個(gè)切片
那么以上變量在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)如下圖所示

所以由上面的分析可以看出來(lái),「切片是依賴于數(shù)組的,而且是一個(gè)指向數(shù)組的指針」,既然切片是指針類型,那么在作為參數(shù)傳遞的時(shí)候,肯定是引用類型,不需要重新copy一份而造成空間浪費(fèi)。
slice 的截取
我們上面說(shuō)過(guò)切片是依賴于數(shù)組的,所以切片的截取是基于數(shù)組進(jìn)行截取的,截取這塊我們直接看例子就行,看例子記住一個(gè)原則即可「左包含,右不包含」
以上例子都符合上面提到的「左包含,右不包含原則」
- s4從下標(biāo)2開(kāi)始截取,截取到下標(biāo)4;
- s5省略了第一個(gè)參數(shù),表示從下標(biāo)0開(kāi)始截??;
- s6省略了第二個(gè)參數(shù),表示截取到最后一個(gè)元素;
- s7省略了兩個(gè)參數(shù),只填寫了中間的冒號(hào):,表示取全部元素;
切片的長(zhǎng)度len()和容量cap()
長(zhǎng)度很好理解,簡(jiǎn)單理解就是「元素的個(gè)數(shù)」,容量相對(duì)難理解一些「在切片引用的底層數(shù)組中從切片的第一個(gè)元素到數(shù)組最后一個(gè)元素的長(zhǎng)度就是切片的容量」。
我們還是來(lái)直接看例子:
- a1是數(shù)組長(zhǎng)度為9,容量也為9,值是從1~9
- s5/s6/s7都是切割數(shù)組a1得到的切片。
- s5的長(zhǎng)度為4,因?yàn)橹挥? 2 3 4這4個(gè)元素,容量為9,因?yàn)閟5切片是從數(shù)組起始位置開(kāi)始切割的:第一個(gè)元素是1,而s5底層數(shù)組a1最后一個(gè)元素是9,1~9共9個(gè)元素,所以s5的容量為9。
- s6的長(zhǎng)度為7,因?yàn)閟6的元素是39這7個(gè)元素;容量也為7,因?yàn)閟5的底層數(shù)組最后一個(gè)元素是9,39共7個(gè)元素,所以s6的容量為7。
- s7更好理解了,長(zhǎng)度和容量都是9,大家自己理解一下。
切片的常用方法
make
make方法主要是用于切片的生成,比較簡(jiǎn)單,比如下面的例子就是我們來(lái)定義一個(gè)長(zhǎng)度為5,容量為10的切片。
append
append主要是用于切片的追加。我們還是直接看例子。
我們可以看到定義了一個(gè)切片,初始化了4個(gè)元素,切片此時(shí)的長(zhǎng)度和容量都為4。
分析:長(zhǎng)度由4變成5,我們很好理解;容量為什么會(huì)從4變成8呢?「這個(gè)是因?yàn)間o語(yǔ)言對(duì)切片的自動(dòng)擴(kuò)容機(jī)制,append追加,如果cap不夠的時(shí)候,go底層會(huì)把底層數(shù)組替換,是go語(yǔ)言的一套擴(kuò)容策略?!?nbsp;簡(jiǎn)單說(shuō)這個(gè)擴(kuò)容機(jī)制就是「如果不夠,就在以前的基礎(chǔ)上翻倍,如果超過(guò)1M,則+1M」,跟redis的bitmap類型的擴(kuò)容機(jī)制是一樣的。
slice 擴(kuò)容的"坑"
這個(gè)坑在面試中經(jīng)常會(huì)遇到,當(dāng) slice 作為函數(shù)參數(shù)時(shí),「如果在函數(shù)內(nèi)部發(fā)生了擴(kuò)容,這時(shí)再修改 slice 中的值是不起作用的」,因?yàn)樾薷陌l(fā)生在新的 array 內(nèi)存中,對(duì)老的 array 內(nèi)存不起作用。
如何追加多個(gè)元素
copy
我們發(fā)現(xiàn)s1和s2是[11 2 3] s3是[1 2 3],說(shuō)明copy方法是復(fù)制了一份,開(kāi)辟了新的內(nèi)存空間,不再引用s1的內(nèi)存地址,這就是兩者的區(qū)別。
如果您覺(jué)得這篇文章還不錯(cuò),記得關(guān)注點(diǎn)贊哦,您的支持是我創(chuàng)作的最大動(dòng)力。





























