中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go36-7-數組和切片

發布時間:2020-08-07 14:26:19 來源:網絡 閱讀:384 作者:騎士救兵 欄目:編程語言

數組和切片

數組(array)類型和切片(slice)類型:
相同:都屬于集合類的類型,它們的值都可以用來存儲某一種類型的值(或者說元素)。
不同:數組的長度是固定的,而切片是可變長的。

長度
數組的長度在聲明的時候必須確定,并且之后不會再變。長度是其類型的一部分。
比如:[1]string 和 [2]string 是兩個不同的類型。
切片的長度是可以隨著其中元素的增長而增長的,但是不會隨著元素的減少而減少。

底層數組
可以把切片看做是對數組的一層簡單的封裝,每個切片的底層數據結構中,一定會包含一個數組。這個數組可以被叫做切片的底層數組。而切片可以被看做是對數組的某個連續片段的引用。

值類型、引用類型

切片屬于引用類型,數組屬于值類型
引用類型:

  • 切片
  • 字典
  • 管道
  • 函數

值類型:

  • 數組
  • 結構體

長度和容量

數組和切片都用長度和容量。調用len函數,可以得到長度,調用cap函數可以得到容量。
數組的容量永遠等于長度,并且是不可變的。
關于切片的容量和長度,看下面的例子:

package main

import "fmt"

func main() {
    s1 := make([]int, 5)
    fmt.Println(len(s1), cap(s1), s1)
    s2 := make([]int, 5, 8)
    fmt.Println(len(s2), cap(s2), s2)
}

先用make聲明了一個[]int類型的變量s1,并且傳遞了一個第二個參數5。指明了切片的長度。
用同樣了方式聲明了切片s2,這次多傳遞了一個參數8,指明了切片的容量。
s1的長度是5,通過聲明指定。容量也是5,聲明時沒有指定容量,就和長度一致。
s2的長度是5,通過聲明指定。容量是8,也是通過聲明進行指定。
下面的切片表達式,可以把s2擴展到其當前最大容量:

s2[0:cap(s2)]

擴容

當切片無法容納更多的元素時,Go語言就會對切片進行擴容。擴容不會改變原來的切片,而是會生成一個容量更大的切片,然后把原有的元素和新元素拷貝到新切片中。
一般情況下,擴容會把新切片的容量(新容量)變成原來切片容量(原容量)的2倍。
當切片的長度大于或等于1024是,擴容是以1.25倍來增加的。
驗證一下上面的擴容策略:

package main

import "fmt"

func main() {
    s1 := make([]int, 3)
    fmt.Println(len(s1), cap(s1), s1)  // 當前容量3
    s1 = append(s1, 1)
    fmt.Println(len(s1), cap(s1), s1)  // 容量翻倍,變成6
    s2 := make([]int, 1023)
    fmt.Println(len(s2), cap(s2))  // 當前容量1023
    s2 = append(s2, 1)
    fmt.Println(len(s2), cap(s2))  // 看著像翻倍,不過是1024的翻倍2048
    s3 := make([]int, 1024)
    s3 = append(s3, 1)
    fmt.Println(len(s3), cap(s3))  // 容量變為1.25倍
}
/* 執行結果
PS G:\Steed\Documents\Go\src\Go36\article07\example02> go run main.go
3 3 [0 0 0]
4 6 [0 0 0 1]
1023 1023
1024 2048
1025 1280
PS G:\Steed\Documents\Go\src\Go36\article07\example02>
*/

驗證下來,似乎有一點小偏差。
另外,如果一次追加的元素過多,按上面的規則做一次擴容不夠,最終還是會擴容到一個比需要的容量大一些或者正好的容量,不過具體情況有點復雜。可以自己試試看,下面的例子一次可以往切片里追加大量的元素:

package main

import "fmt"

func main() {
    s1 := make([]int, 5, 8)
    var s []int
    s = append(s1, make([]int, 88-5)...)
    fmt.Println(len(s), cap(s))
    s2 := make([]int, 1024)
    s = append(s2, make([]int, 2048-1024)...)
    fmt.Println(len(s), cap(s))
}

不必太在意切片“擴容”策略中的一些細節,只要能夠理解它的基本規律,并可以進行近似的估算就可以了。
不過如果有興趣,更多細節可參見runtime包中slice.go文件里的growslice及相關函數的具體實現。

替換底層數組

無需擴容時,append函數返回的是指向原底層數組的新切片。其實就是底層數組還在那,切片的下標往后加了幾位,可以指向到底層數組后面更多的元素了。
需要擴容時,append函數返回的是指向新底層數組的新切片。會創建一個更大容量的新的底層數組,將元素從原切片復制到新的底層數組,然后追加新元素。
希望下面的例子可以說明這里的問題:

package main

import "fmt"

func main() {
    a := [...]int{1,2,3,4,5}  // 這是一個數組,將作為下面切片的底層數組
    s1 := a[:3]
    s1 = append(s1, 11)  // 未發生擴容
    fmt.Println(s1, a)  // s1的新底層數組還是a,往s1末尾添加元素,將覆蓋a里原來的值
    s2 := a[:3]
    s2 = append(s2, 21, 22, 23, 24, 25)  // 容量不夠,需要擴容
    fmt.Print(s2, a)  // 現在a不再是s2的底層數組了,這里會復制一份數組到一個新的數組,作為新的底層數組。a里的元素不會被覆蓋
}

這里在生成數組a的時候推導了數組的長度,而長度也是數組類型的一部分,用上面的方法也可以把長度推導出來。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

荥经县| 乌什县| 青河县| 静宁县| 驻马店市| 青冈县| 曲麻莱县| 阳原县| 景泰县| 卓资县| 崇仁县| 江山市| 满城县| 布尔津县| 乐都县| 称多县| 辉县市| 乌拉特中旗| 托克逊县| 丘北县| 怀远县| 兴仁县| 锦州市| 将乐县| 东乡县| 揭东县| 永州市| 海口市| 珠海市| 平邑县| 新巴尔虎右旗| 工布江达县| 广平县| 紫云| 铜梁县| 汕头市| 阿城市| 台北市| 乐安县| 广河县| 浮山县|