快速理解Go數組和切片的內部實現原理

來源:互聯網
上載者:User

很多人對Go語言的arrayslice傻傻分不清楚,今天我們就從底層出發,來聊聊它倆到底有什麼區別。

數組

幾乎所有電腦語言,數組的實現都是相似的:一段連續的記憶體,Go語言也一樣,Go語言的數組底層實現就是一段連續的記憶體空間。每個元素有唯一一個索引(或者叫下標)來訪問。如所示,是[5]int{1:10, 2:20}數組的內部實現邏輯圖:

由於記憶體連續,CPU很容易計算索引(即數組的下標),可以快速迭代數組裡的所有元素。
Go語言的數組不同於C語言或者其他語言的數組,C語言的陣列變數是指向數組第一個元素的指標;而Go語言的數組是一個值,Go語言中的數組是實值型別,一個陣列變數就表示著整個數組,意味著Go語言的數組在傳遞的時候,傳遞的是原數組的拷貝。你可以理解為Go語言的數組是一種有序的struct

slice

切片是一個很小的對象,是對數組進行了抽象,並提供相關的操作方法。切片有三個屬性欄位:長度、容量和指向數組的指標。

中,ptr指的是指向array的pointer,len是指切片的長度, cap指的是切片的容量。現在,我想你對數組和切片有了一個本質的認識。

切片有多種聲明方式,每種初始化方式對應的邏輯圖是怎樣的呢?

對於s := make([]byte, 5)s := []byte{...}的方式

對於s = s[2:4]的方式

對於nil的切片即var s []byte對應的邏輯圖是

在此有一個說明:nil切片和切片是不太一樣的,空切片即s := make([]byte, 0)或者s := []byte{}出來的切片
空切片的邏輯圖為:

空切片指標不為nil,而nil切片指標為nil。但是,不管是空切片還是nil切片,對其調用內建函數append()lencap的效果都是一樣的,感受不到任何區別。

擴容

slice這種資料結構便於使用和管理資料集合,可以理解為是一種“動態數組”,slice也是圍繞動態數組的概念來構建的。既然是動態數組,那麼slice是如何擴容的呢?

請記住以下兩條規則:

  • 如果切片的容量小於1024個元素,那麼擴容的時候slice的cap就翻番,乘以2;一旦元素個數超過1024個元素,增長因子就變成1.25,即每次增加原來容量的四分之一。
  • 如果擴容之後,還沒有觸及原數組的容量,那麼,切片中的指標指向的位置,就還是原數組,如果擴容之後,超過了原數組的容量,那麼,Go就會開闢一塊新的記憶體,把原來的值拷貝過來,這種情況絲毫不會影響到原數組。

知道了一下規則,請看下面程式,試問輸出結果:

import (    "fmt")func main(){    array := [4]int{10, 20, 30, 40}    slice := array[0:2]    newSlice := append(append(append(slice, 50), 100), 150)    newSlice[1] += 1    fmt.Println(slice)}

輸出:

[10 20]

答對了嗎?

參考文獻:
《Go in action》
https://blog.golang.org/go-slices-usage-and-internals

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.