<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文詳解Go語言之Slice

          共 3252字,需瀏覽 7分鐘

           ·

          2022-05-23 02:31

          一、什么是slice


          slice翻譯成中文是切片的意思,而在go編程中slice是一個(gè)數(shù)據(jù)類型,其代表一個(gè)列表,類似于java中的List。我們可以為每一種go中的基礎(chǔ)類型或自定義類型創(chuàng)建對應(yīng)的切片。在這里我們可以將slice理解成一個(gè)列表,而在日常開發(fā)中不管是使用什么語言,都需要經(jīng)常用到列表這種數(shù)據(jù)結(jié)構(gòu),比如java中的List,我們在日常使用Java的開發(fā)中十分常見。而與java不同的是go將列表也就是slice作為一種基本類型,而不是List這樣的封裝類。


          二、slice的結(jié)構(gòu)


          slice結(jié)構(gòu)如下,其內(nèi)部存放了指向底層數(shù)組的指針、len(長度)、cap(容量)


          三、slice 實(shí)現(xiàn)原理


          Slice又稱動(dòng)態(tài)數(shù)組,依托數(shù)組實(shí)現(xiàn),可以方便的進(jìn)行擴(kuò)容、傳遞等,實(shí)際使用中比數(shù)組更靈活。Slice 依托數(shù)組實(shí)現(xiàn),底層數(shù)組對用戶屏蔽,在底層數(shù)組容量不足時(shí)可以實(shí)現(xiàn)自動(dòng)重分配并生成新的 Slice 。?

          源碼包中 src/runtime/slice.go:slice 定義了 Slice 的數(shù)據(jù)結(jié)構(gòu):?
          type?slice?struct?{?
          ?????array?unsafe.Pointer?
          ?????len???int?
          ?????cap???int
          }?

          從數(shù)據(jù)結(jié)構(gòu)看Slice很清晰, array指針指向底層數(shù)組,len表示切片長度,cap表示底層數(shù)組容量。

          3.1 使用make創(chuàng)建Slice

          使用 make 來創(chuàng)建 Slice 時(shí),可以同時(shí)指定長度和容量,創(chuàng)建時(shí)底層會(huì)分配一個(gè)數(shù)組,數(shù)組的長度即容量。例如,語句 slice := make([]int, 5, 10) 所創(chuàng)建的 Slice ,結(jié)構(gòu)如下圖所示:

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

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

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

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

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


          四、Slice 擴(kuò)容


          4.1、slice 擴(kuò)容影響原數(shù)組

          append 函數(shù)會(huì)改變 slice 所引用的數(shù)組的內(nèi)容,從而影響到引用同一數(shù)組的其它 slice。但當(dāng) slice 中沒有剩余空間(即(cap-len) == 0)時(shí),此時(shí)將動(dòng)態(tài)分配新的數(shù)組空間。返回的slice 數(shù)組指針將指向這個(gè)空間,而原數(shù)組的內(nèi)容將保持不變;其它引用此數(shù)組的 slice 則不受影響。

          func?testSlice()?{
          ?var?ar?=?[...]byte{'a',?'b',?'c',?'d',?'e',?'f',?'g',?'h'}
          ?//?打印結(jié)果:abcdefgh
          ?fmt.Printf("%s?\n",?ar)
          ?slice1?:=?ar[2:5]
          ?//?注:append 函數(shù)會(huì)改變 slice 所引用的數(shù)組的內(nèi)容,從而影響到引用同一數(shù)組的其它 slice。
          ?//?但當(dāng)?slice?中沒有剩余空間(即(cap-len)?==?0)時(shí),此時(shí)將動(dòng)態(tài)分配新的數(shù)組空間。返回的
          ?// slice 數(shù)組指針將指向這個(gè)空間,而原數(shù)組的內(nèi)容將保持不變;其它引用此數(shù)組的 slice 則不受影響。
          ?slice1?=?append(slice1,?'A')
          ?//?打印結(jié)果:cdeA
          ?fmt.Printf("%s?\n",?slice1)
          ?//?打印結(jié)果:abcdeAgh
          ?fmt.Printf("%s?\n",?ar)
          }

          4.2、slice 擴(kuò)容注意事項(xiàng)

          使用 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ò)容,如下圖所示:

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

          4.3、擴(kuò)容容量的選擇遵循以下規(guī)則:

          1. 如果原Slice 容量小于 1024 ,則新 Slice 容量將擴(kuò)大為原來的 2 倍;

          2. 如果原Slice 容量大于等于 1024 ,則新 Slice 容量將擴(kuò)大為原來的 1.25 倍;

          4.4、使用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 。


          五、常見的slice的坑


          slice到底是值傳遞還是引用傳遞?

          對于這個(gè)問題我相信很多人都對此有爭議,我們先來看一段代碼:

          在上面這段代碼中,我們定義了一個(gè)長度len為5的切片s,并將s賦值給了t,之后我們將t[0]的值修改成了99,最終我們發(fā)現(xiàn),s[0]的值也發(fā)生了改變,以當(dāng)前的現(xiàn)象來看slice是引用傳遞,我們先不急,再來看一段代碼。

          在這段代碼中我們依然定義了一個(gè)長度為5,容量為10的切片s,并將s賦值給了t,然后向t中添加了一個(gè)元素6。分別打印s跟t,我們發(fā)現(xiàn)這次打印出來的內(nèi)容并不一致,從這個(gè)現(xiàn)象看來又好像是值傳遞。這時(shí)候可能有些人會(huì)有些疑惑,為什么同時(shí)表現(xiàn)出了值傳遞與引用傳遞的現(xiàn)象。我們再來看一段代碼。

          這次我們在代碼2的基礎(chǔ)上分別打印了 s 與 t 的len、cap與底層數(shù)組的地址,我們發(fā)現(xiàn) s 的len為5,t 的len為6,除此之外cap與底層數(shù)組的地址都是一致的。因此我們可以得出結(jié)論,slice在go中的應(yīng)該是值傳遞,只不過當(dāng)將 s 賦值給 t 時(shí)底層數(shù)組指針指向的是同一個(gè)底層數(shù)組,而len與cap都是拷貝的副本,所以 t 在append之后len發(fā)生變化而 s 中的len并不會(huì)因此發(fā)生改變,其傳遞過程如下:

          切片slice的坑非常多,在這也只是給大家展示了一種,經(jīng)常有很多學(xué)員給我說:明明自己已經(jīng)很小心了,但千防萬防還是掉進(jìn)slice的坑里了。

          為了幫助廣大學(xué)員對Go語言中切片(slice)有一個(gè)系統(tǒng)而全面的掌握,避免掉坑,我們特別邀請張朝陽老師為大家開啟一場《slice避坑指南》的直播之旅。


          張朝陽老師是華中科技大學(xué)的碩士,資深Go語言專家,多次舉行Go專題公開課。可以說聽完張朝陽老師的這節(jié)課,你會(huì)對Go語言中切片(slice)有一個(gè)非常全面的認(rèn)識(shí),完美避開slice中遇到的95%的坑。

          本次課程向所有學(xué)員免費(fèi)公開,課程難易程度上大家也完全不用擔(dān)心,張朝陽老師有深厚的授課功底,非常擅于將抽象的知識(shí)具體化,所以只要你有一定Go語言的基礎(chǔ),就聽得懂、學(xué)的會(huì)。

          本次直播時(shí)間:5月19日晚8點(diǎn)

          掃碼進(jìn)入直播間
          ??????


          文章參考鏈接:

          https://blog.csdn.net/xiaohei_buhei/article/details/122681538

          https://blog.csdn.net/qq_40880022/article/details/123997549


          瀏覽 168
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操网址 | 成人在线无码影视 | 国产尤物视频 | 在线能看的丝袜网站 | 免费看小黄片 |