欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Go語言中切片的長度與容量的區(qū)別

 更新時間:2022年11月02日 11:01:14   作者:TimLiu  
切片可以看成是數(shù)組的引用,切片的長度是它所包含的元素個數(shù)。切片的容量是從它的第一個元素到其底層數(shù)組元素末尾的個數(shù)。本文將通過示例詳細(xì)講講Go語言中切片的長度與容量的區(qū)別,需要的可以參考一下

切片的聲明

切片可以看成是數(shù)組的引用(實(shí)際上切片的底層數(shù)據(jù)結(jié)構(gòu)確實(shí)是數(shù)組)。在 Go 中,每個數(shù)組的大小是固定的,不能隨意改變大小,切片可以為數(shù)組提供動態(tài)增長和縮小的需求,但其本身并不存儲任何數(shù)據(jù)。

// 數(shù)組的聲明
var a [5]int //只指定長度,元素初始化為默認(rèn)值0
var a [5]int{1,2,3,4,5}

// 切片的聲明
// 方法1:直接初始化
var s []int //聲明一個長度和容量為 0 的 nil 切片
var s []int{1,2,3,4,5} // 同時創(chuàng)建一個長度為5的數(shù)組
// 方法2:用make()函數(shù)來創(chuàng)建切片
var s = make([]int, 0, 5)

// 切分?jǐn)?shù)組:var 變量名 []變量類型 = arr[low, high],low和high為數(shù)組的索引。
// 記住規(guī)則為:左閉右開
var arr = [5]int{1,2,3,4,5}
var slice []int = arr[1:4] // [2,3,4]

切片的長度和容量

切片的長度是它所包含的元素個數(shù)。切片的容量是從它的第一個元素到其底層數(shù)組元素末尾的個數(shù)。切片 s 的長度和容量可通過表達(dá)式 len(s) 和 cap(s) 來獲取。

s := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(s, len(s), cap(s))
// output: [0 1 2 3 4 5 6 7 8 9] 10 10

s1 := s[0:5]
fmt.Println(s1, len(s1), cap(s1))
// output: [0 1 2 3 4] 5 10

s2 := s[5:]
fmt.Println(s2, len(s2), cap(s2))
// output: [5 6 7 8 9] 5 5

切片追加元素后長度和容量的變化

append 函數(shù)

Go 提供了內(nèi)建的 append 函數(shù),為切片追加新的元素。

func append(s []T, vs ...T) []T

append 的返回值是一個包含原切片所有元素加上新添加元素的切片。

s := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(s, len(s), cap(s))
sResult := append(s, 11)
fmt.Println(sResult, len(sResult), cap(sResult))
// output: 
// [0 1 2 3 4 5 6 7 8 9] 10 10
// [0 1 2 3 4 5 6 7 8 9 11] 11 20

這個時候,我們就可以發(fā)現(xiàn),當(dāng)我們 append 元素進(jìn)入切片時,原切片的長度以及容量都發(fā)生了變化,但是它們的變化為什么會這樣呢?

下面我們一起看看源碼是怎么實(shí)現(xiàn)的。

切片的源代碼學(xué)習(xí)

Go 中切片的數(shù)據(jù)結(jié)構(gòu)可以在源碼下的 src/runtime/slice.go 中查看。以下源代碼基于 go1.16.7 版本。

切片的結(jié)構(gòu)體

切片作為數(shù)組的引用,有三個屬性字段:指向數(shù)組的指針、長度和容量。

type slice struct {
  // 指向底層數(shù)組的指針
	array unsafe.Pointer
  // slice 當(dāng)前元素個數(shù),即 len() 時返回的數(shù)
	len   int
  // slice 的容量,即 cap() 時返回的數(shù)
	cap   int
}

切片的擴(kuò)容

slice 通過調(diào)用 append 函數(shù)來針對slice進(jìn)行尾部追加元素,如果此時 slice 的 cap 值小于當(dāng)前 len 加上 append 中傳入值的數(shù)量,就會調(diào)用 runtime.growslice 函數(shù),進(jìn)行擴(kuò)容。

我們這里只放出基本的擴(kuò)容規(guī)則的代碼解析,如果對內(nèi)存對齊、數(shù)據(jù)拷貝等感興趣,可自行查看對應(yīng)的源碼。

基本擴(kuò)容規(guī)則

func growslice(et *_type, old slice, cap int) slice {
    newcap := old.cap
    doublecap := newcap + newcap
    // 如果新容量大于舊容量的兩倍,則直接按照新容量大小申請
    if cap > doublecap {
			newcap = cap
    } else {
        // 如果原有長度小于1024,則新容量是舊容量的2倍
        if old.len < 1024 {
            newcap = doublecap
        } else {
            // 按照原有容量的 1/4 增加,直到滿足新容量的需要
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            if newcap <= 0 {
                newcap = cap
            }
        }
    }
}

從源碼來看,實(shí)際上可以整理出幾個規(guī)則:

當(dāng)原切片長度小于 1024 時,新的切片長度直接加上 append 元素的個數(shù),容量則會直接 *2

當(dāng)原切片長度大于等于 1024 時,新的切片長度直接加上 append 元素的個數(shù),容量則會增加 1/4

總結(jié)

切片是一個結(jié)構(gòu)體,保存著切片的容量,長度以及指向數(shù)組的指針(數(shù)組的地址)。

從源碼來看,當(dāng)一個切片進(jìn)行擴(kuò)容時,會進(jìn)行 growslice,這是一個花銷較大的操作,在日常開發(fā)中,如果能明確知道切片的長度或者容量時,我們需要在初始化的時候聲明,避免切片頻繁擴(kuò)容而帶來的花銷。

到此這篇關(guān)于詳解Go語言中切片的長度與容量的區(qū)別的文章就介紹到這了,更多相關(guān)Go語言 切片長度與容量內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang優(yōu)雅關(guān)閉channel的方法示例

    Golang優(yōu)雅關(guān)閉channel的方法示例

    Goroutine和channel是Go在“并發(fā)”方面兩個核心feature,下面這篇文章主要給大家介紹了關(guān)于Golang如何優(yōu)雅關(guān)閉channel的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考解決,下面來一起看看吧。
    2017-11-11
  • Go反射中type和kind區(qū)別比較詳析

    Go反射中type和kind區(qū)別比較詳析

    這篇文章主要給大家介紹了關(guān)于Go反射中type和kind區(qū)別比較的相關(guān)資料,Type是接口類型,Value是Struct類型,Type是類型描述,而Value是具體的值,需要的朋友可以參考下
    2023-10-10
  • 最新評論