[go語(yǔ)言]-slice實(shí)現(xiàn)的使用和基本原理

[toc]



摘要

本文主要回顧一下Slice實(shí)現(xiàn)的使用和基本原理

Slice數(shù)據(jù)結(jié)構(gòu)

源碼包中 src/runtime/slice.go:slice 定義了Slice的數(shù)據(jù)結(jié)構(gòu): array指針指向底層數(shù)組,len表示切片長(zhǎng)度屈呕,cap表示底層數(shù)組容量微宝。

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

使用make創(chuàng)建Slice

image-20201220190357622

該Slice長(zhǎng)度為5,即可以使用下標(biāo)slice[0] ~ slice[4]來操作里面的元素虎眨,capacity為10蟋软,表示后續(xù)向 slice添加新的元素時(shí)可以不必重新分配內(nèi)存,直接使用預(yù)留內(nèi)存即可嗽桩。

使用數(shù)組創(chuàng)建Slice

使用數(shù)組來創(chuàng)建Slice時(shí)岳守,Slice將與原數(shù)組共用一部分內(nèi)存。 例如碌冶,語(yǔ)句 slice := array[5:7] 所創(chuàng)建的Slice湿痢,結(jié)構(gòu)如下圖所示:

image-20201220190451870

切片從數(shù)組array[5]開始,到數(shù)組array[7]結(jié)束(不含array[7])扑庞,即切片長(zhǎng)度為2譬重,數(shù)組后面的內(nèi)容都作為切 片的預(yù)留內(nèi)存,即capacity為5罐氨。

  • 數(shù)組和切片操作可能作用于同一塊內(nèi)存臀规,這也是使用過程中需要注意的地方。

Slice 擴(kuò)容

使用append向Slice追加元素時(shí)栅隐,如果Slice空間不足塔嬉,將會(huì)觸發(fā)Slice擴(kuò)容,擴(kuò)容實(shí)際上重新一配一塊更大的內(nèi) 存租悄,將原Slice數(shù)據(jù)拷貝進(jìn)新Slice谨究,然后返回新Slice,擴(kuò)容后再將數(shù)據(jù)追加進(jìn)去泣棋。

例如记盒,當(dāng)向一個(gè)capacity為5,且length也為5的Slice再次追加1個(gè)元素時(shí)外傅,就會(huì)發(fā)生擴(kuò)容纪吮,如下圖所示:

image-20201220190643601

擴(kuò)容操作只關(guān)心容量俩檬,會(huì)把原Slice數(shù)據(jù)拷貝到新Slice,追加數(shù)據(jù)由append在擴(kuò)容結(jié)束后完成碾盟。上圖可見棚辽,擴(kuò)容后 新的Slice長(zhǎng)度仍然是5,但容量由5提升到了10冰肴,原Slice的數(shù)據(jù)也都拷貝到了新Slice指向的數(shù)組中屈藐。

擴(kuò)容容量的選擇遵循以下規(guī)則: 如果原Slice容量小于1024,則新Slice容量將擴(kuò)大為原來的2倍;
如果原Slice容量大于等于1024熙尉,則新Slice容量將擴(kuò)大為原來的1.25倍; 使用append()向Slice添加一個(gè)元素的實(shí)現(xiàn)步驟如下:

  1. 假如Slice容量夠用联逻,則將新元素追加進(jìn)去,Slice.len++检痰,返回原Slice
  2. 原Slice容量不夠包归,則將Slice先擴(kuò)容,擴(kuò)容后得到新Slice
  3. 將新元素追加進(jìn)新Slice铅歼,Slice.len++公壤,返回新的Slice。
image-20201220191523290

Slice Copy

使用copy()內(nèi)置函數(shù)拷貝兩個(gè)切片時(shí)椎椰,會(huì)將源切片的數(shù)據(jù)逐個(gè)拷貝到目的切片指向的數(shù)組中厦幅,拷貝數(shù)量取兩個(gè)切片長(zhǎng)度的最小值。

例如長(zhǎng)度為10的切片拷貝到長(zhǎng)度為5的切片時(shí)慨飘,將會(huì)拷貝5個(gè)元素确憨。 也就是說,copy過程中不會(huì)發(fā)生擴(kuò)容瓤的。

特殊切片

跟據(jù)數(shù)組或切片生成新的切片一般使用 slice := array[start:end] 方式缚态,這種新生成的切片并沒有指定切片的容量, 實(shí)際上新切片的容量是從start開始直至array的結(jié)束堤瘤。

比如下面兩個(gè)切片玫芦,長(zhǎng)度和容量都是一致的,使用共同的內(nèi)存地址:

sliceA := make([]int, 5, 10) 
sliceB := sliceA[0:5]

根據(jù)數(shù)組或切片生成切片還有另一種寫法本辐,即切片同時(shí)也指定容量桥帆,即slice[start:end:cap], 其中cap即為新 切片的容量,當(dāng)然容量不能超過原切片實(shí)際值慎皱,如下所示:

sliceA := make([]int, 5, 10) //length = 5; capacity = 10
sliceB := sliceA[0:5]            //length = 5; capacity = 10
sliceC := sliceA[0:5:5]          //length = 5; capacity = 5

這切片方法不常見老虫,在Golang源碼里能夠見到,不過非常利于切片的理解茫多。

總結(jié)

  • 創(chuàng)建切片時(shí)可跟據(jù)實(shí)際需要預(yù)分配容量祈匙,盡量避免追加過程中擴(kuò)容操作,有利于提升性能;
  • 切片拷貝時(shí)需要判斷實(shí)際拷貝的元素個(gè)數(shù)
  • 謹(jǐn)慎使用多個(gè)切片操作同一個(gè)數(shù)組,以防讀寫沖突
  • 每個(gè)切片都指向一個(gè)底層數(shù)組
  • 每個(gè)切片都保存了當(dāng)前切片的長(zhǎng)度夺欲、底層數(shù)組可用容量
  • 使用len()計(jì)算切片長(zhǎng)度時(shí)間復(fù)雜度為O(1)跪帝,不需要遍歷切片
  • 使用cap()計(jì)算切片容量時(shí)間復(fù)雜度為O(1),不需要遍歷切片
  • 通過函數(shù)傳遞切片時(shí)些阅,不會(huì)拷貝整個(gè)切片伞剑,因?yàn)榍衅旧碇皇莻€(gè)結(jié)構(gòu)體而矣
  • 使用append()向切片追加元素時(shí)有可能觸發(fā)擴(kuò)容,擴(kuò)容后將會(huì)生成新的切片

參考

《go專家編程》


你的鼓勵(lì)也是我創(chuàng)作的動(dòng)力

打賞地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末市埋,一起剝皮案震驚了整個(gè)濱河市黎泣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缤谎,老刑警劉巖抒倚,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異坷澡,居然都是意外死亡托呕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門洋访,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镣陕,“玉大人谴餐,你說我怎么就攤上這事姻政。” “怎么了岂嗓?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵汁展,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我厌殉,道長(zhǎng)食绿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任公罕,我火速辦了婚禮器紧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘楼眷。我一直安慰自己铲汪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布罐柳。 她就那樣靜靜地躺著掌腰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪张吉。 梳的紋絲不亂的頭發(fā)上齿梁,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼勺择。 笑死创南,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的酵幕。 我是一名探鬼主播扰藕,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼芳撒!你這毒婦竟也來了邓深?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤笔刹,失蹤者是張志新(化名)和其女友劉穎芥备,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舌菜,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萌壳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了日月。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袱瓮。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖爱咬,靈堂內(nèi)的尸體忽然破棺而出尺借,到底是詐尸還是另有隱情,我是刑警寧澤精拟,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布燎斩,位于F島的核電站,受9級(jí)特大地震影響蜂绎,放射性物質(zhì)發(fā)生泄漏栅表。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一师枣、第九天 我趴在偏房一處隱蔽的房頂上張望怪瓶。 院中可真熱鬧,春花似錦践美、人聲如沸洗贰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哆姻。三九已至,卻和暖如春玫膀,著一層夾襖步出監(jiān)牢的瞬間矛缨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留箕昭,地道東北人灵妨。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像落竹,于是被迫代替她去往敵國(guó)和親泌霍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容