自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

咱們來重新認識一下Golang的切片

開發(fā) 前端
我們先來看一下Golang中的數(shù)組,大家都知道Golang其實是c語言寫的,那么在數(shù)組這一塊Golang和c語言的含義一樣么?當然是不一樣的。

今天廢話不用多說,咱們來直接進入正題

切片究竟是什么?

在聊切片之前,我們先來看一下golang中的數(shù)組,大家都知道golang其實是c語言寫的,那么在數(shù)組這一塊golang和c語言的含義一樣么?當然是不一樣的。

golang數(shù)組

  • Go數(shù)組是值語義的,這意味著一個數(shù)組變量表示的是「整個數(shù)組」。
  • Go語言中傳遞數(shù)組是純粹的「值拷貝」。

c語言數(shù)組

  • 數(shù)組變量可視為指向數(shù)組「第一個元素的指針」。

因為golang中數(shù)組是純粹的值拷貝,所以在golang中,更地道的方式是使用「切片」, 「切片之于數(shù)組就像是文件描述符之于文件」數(shù)組更多是“退居幕后”,承擔的是底層存儲空間的角色;而切片則走向“前臺”,為底層的存儲(數(shù)組)打開了一個訪問的“窗口”。

圖片

切片和數(shù)組的關系

其實通過golang源碼也可以看出來,其實切片就是數(shù)組的指針。

//$GOROOT/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

如何聲明一個切片?

方式一

s := make([]byte, 5)

圖片

我們看到通過上述語句創(chuàng)建的切片,編譯器會自動為切片建立一個「底層數(shù)組」,如果沒有在make中指定cap參數(shù),那么cap = len,即編譯器建立的數(shù)組長度為len。

方式二(數(shù)組切片化)

u := [10]byte{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
s := u[3:7]

圖片

數(shù)組切片化

  • 切片s打開了一個操作數(shù)組u的窗口。
  • 切片截取數(shù)組是「左包含右不包含」的原則。比如u[3,7]為包含u[3]但是不包含u[7]。
  • 「切片的長度len」為4,計算方式為(high-low),在這個case中也就是7-3=4。
  • 「切片的容量cap」為s的第一個元素s[0]到數(shù)組u的末尾,所以是7。

當然可以基于一個數(shù)組建立多個切片

u := [10]byte{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
s1 := u[1:5]
s2 := u[6:9]
s3 := u[3:7]

圖片

基于一個數(shù)組建立多個切片

也可以基于已有切片再次創(chuàng)建切片,也叫reslicing

u := [10]byte{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
s1 := u[1:5]
s2 := s1[2:4]

圖片

reslicing

動態(tài)擴容

在講動態(tài)擴容之前,我們先來看一些例子。

// chapter3/sources/slice_append.go
var s []int  // s被賦予零值nil
s = append(s, 11)
fmt.Println(len(s), cap(s)) //1 1
s = append(s, 12)
fmt.Println(len(s), cap(s)) //2 2
s = append(s, 13)
fmt.Println(len(s), cap(s)) //3 4
s = append(s, 14)
fmt.Println(len(s), cap(s)) //4 4
s = append(s, 15)
fmt.Println(len(s), cap(s)) //5 8

我們看到切片s的len值是線性增長的,但cap值卻呈現(xiàn)出不規(guī)則的變化。通過下圖我們更容易看清楚多次append操作究竟是如何讓切片進行動態(tài)擴容的。

圖片

動態(tài)擴容

我們看到append會根據(jù)切片的需要,在「當前底層數(shù)組容量無法滿足」的情況下,「動態(tài)分配新的數(shù)組」,新數(shù)組長度會按一定算法擴展(參見$GOROOT/src/runtime/slice.go中的growslice函數(shù))。新數(shù)組建立后,append會把「舊數(shù)組中的數(shù)據(jù)復制到新數(shù)組中」,之后新數(shù)組便成為切片的底層數(shù)組,舊數(shù)組后續(xù)會被「垃圾回收」掉。

這樣的append操作有時會給Gopher帶來一些困惑,比如通過語法u[low: high]形式進行數(shù)組切片化而創(chuàng)建的切片,一旦切片cap觸碰到數(shù)組的上界,再對切片進行append操作,切片就會和原數(shù)組解除綁定。

小結(jié)練習

根據(jù)自己對切片的理解,先看看自己能不能想到每一步結(jié)果都會輸出啥。

// chapter3/sources/slice_unbind_orig_array.go

func main() {
    u := []int{11, 12, 13, 14, 15}
    fmt.Println("array:", u) // [11, 12, 13, 14, 15]
    s := u[1:3]
    fmt.Printf("slice(len=%d, cap=%d): %v\n", len(s), cap(s), s) // [12, 13]
    s = append(s, 24)
    fmt.Println("after append 24, array:", u)
    fmt.Printf("after append 24, slice(len=%d, cap=%d): %v\n", len(s), cap(s), s)
    s = append(s, 25)
    fmt.Println("after append 25, array:", u)
    fmt.Printf("after append 25, slice(len=%d, cap=%d): %v\n", len(s), cap(s), s)
    s = append(s, 26)
    fmt.Println("after append 26, array:", u)
    fmt.Printf("after append 26, slice(len=%d, cap=%d): %v\n", len(s), cap(s), s)

    s[0] = 22
    fmt.Println("after reassign 1st elem of slice, array:", u)
    fmt.Printf("after reassign 1st elem of slice, slice(len=%d, cap=%d): %v\n", len(s), cap(s), s)
}

答案揭曉

$go run slice_unbind_orig_array.go
array: [11 12 13 14 15]
slice(len=2, cap=4): [12 13]
after append 24, array: [11 12 13 24 15]
after append 24, slice(len=3, cap=4): [12 13 24]
after append 25, array: [11 12 13 24 25]
after append 25, slice(len=4, cap=4): [12 13 24 25]
after append 26, array: [11 12 13 24 25]
after append 26, slice(len=5, cap=8): [12 13 24 25 26]
after reassign 1st elem of slice, array: [11 12 13 24 25]
after reassign 1st elem of slice, slice(len=5, cap=8): [22 13 24 25 26]

我們看到在添加元素25之后,切片的元素已經(jīng)觸碰到底層數(shù)組u的邊界;此后再添加元素26,append發(fā)現(xiàn)底層數(shù)組已經(jīng)無法滿足添加新元素的要求,于是新創(chuàng)建了一個底層數(shù)組(數(shù)組長度為cap(s)的2倍,即8),并將原切片的元素復制到新數(shù)組中。在這之后,即便再修改切片中的元素值,原數(shù)組u的元素也沒有發(fā)生任何改變,因為此時切片s與數(shù)組u已經(jīng)解除了綁定關系,s已經(jīng)不再是數(shù)組u的描述符了。

責任編輯:姜華 來源: 程序員小飯
相關推薦

2022-09-08 13:58:39

Spring高并發(fā)異步

2020-10-15 07:13:53

算法監(jiān)控數(shù)據(jù)

2022-12-07 08:13:55

CNI抽象接口

2019-11-28 10:40:45

Kafka架構(gòu)KafkaConsum

2018-04-02 09:07:36

CIO

2014-01-06 11:23:54

Mesos設計架構(gòu)

2023-05-29 08:32:40

JAVA重寫重載

2013-04-17 11:21:59

Windows PhoWindows Pho

2018-12-24 09:51:22

CPU天梯圖Inter

2024-05-27 00:00:00

AmpPHP非阻塞

2021-04-22 21:15:38

Generator函數(shù)生成器

2010-10-22 11:10:24

軟考

2021-11-11 05:00:02

JavaMmap內(nèi)存

2019-02-24 21:27:26

物聯(lián)網(wǎng)網(wǎng)關物聯(lián)網(wǎng)IOT

2019-10-31 13:40:52

JavaPHP編程語言

2016-11-07 11:34:28

數(shù)據(jù)可視化大數(shù)據(jù)

2016-12-13 15:41:40

JavaHashMap

2017-01-03 17:22:16

公共云安全

2020-09-17 07:08:04

TypescriptVue3前端

2019-09-02 08:53:46

程序員
點贊
收藏

51CTO技術棧公眾號