真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

go語言append源碼 go語言示例

GoLang中的切片擴(kuò)容機(jī)制

[5]int 是數(shù)組,而 []int 是切片。二者看起來相似,實(shí)則是根本上不同的數(shù)據(jù)結(jié)構(gòu)。

創(chuàng)新互聯(lián)建站主要從事網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)臺(tái)兒,十余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575

切片的數(shù)據(jù)結(jié)構(gòu)中,包含一個(gè)指向數(shù)組的指針 array ,當(dāng)前長(zhǎng)度 len ,以及最大容量 cap 。在使用 make([]int, len) 創(chuàng)建切片時(shí),實(shí)際上還有第三個(gè)可選參數(shù) cap ,也即 make([]int, len, cap) 。在不聲明 cap 的情況下,默認(rèn) cap=len 。當(dāng)切片長(zhǎng)度沒有超過容量時(shí),對(duì)切片新增數(shù)據(jù),不會(huì)改變 array 指針的值。

當(dāng)對(duì)切片進(jìn)行 append 操作,導(dǎo)致長(zhǎng)度超出容量時(shí),就會(huì)創(chuàng)建新的數(shù)組,這會(huì)導(dǎo)致和原有切片的分離。在下例中

由于 a 的長(zhǎng)度超出了容量,所以切片 a 指向了一個(gè)增長(zhǎng)后的新數(shù)組,而 b 仍然指向原來的老數(shù)組。所以之后對(duì) a 進(jìn)行的操作,對(duì) b 不會(huì)產(chǎn)生影響。

試比較

本例中, a 的容量為6,因此在 append 后并未超出容量,所以 array 指針沒有改變。因此,對(duì) a 進(jìn)行的操作,對(duì) b 同樣產(chǎn)生了影響。

下面看看用 a := []int{} 這種方式來創(chuàng)建切片會(huì)是什么情況。

可以看到,空切片的容量為0,但后面向切片中添加元素時(shí),并不是每次切片的容量都發(fā)生了變化。這是因?yàn)?,如果增大容量,也即需要?jiǎng)?chuàng)建新數(shù)組,這時(shí)還需要將原數(shù)組中的激襪所有元素復(fù)制到新數(shù)組中,開銷游遲很大,所以GoLang設(shè)計(jì)了一套擴(kuò)容機(jī)制,以減少需要?jiǎng)?chuàng)建新數(shù)組的次數(shù)。但這導(dǎo)致無法很直接地判斷 append 時(shí)是否創(chuàng)建了新數(shù)組。

如果一次添加多個(gè)元素,容量又會(huì)怎樣變化呢?試比較下面兩個(gè)例子:

那么,是不是說,當(dāng)向一個(gè)空切片中插入 2n-1 個(gè)元素時(shí),容量就會(huì)被設(shè)置為 2n 呢?我們來試試其他的數(shù)據(jù)類型。

可以看到,根據(jù)切片對(duì)應(yīng)數(shù)據(jù)類型的不同,容量增長(zhǎng)的方式也有很大的區(qū)別。相關(guān)的源碼包括: src/runtime/msize.go , src/runtime/mksizeclasses.go 等。

我們?cè)倏纯辞衅跏挤强盏那樾巍?/p>

可以看到,與剛剛向空切片添加5個(gè)int的情況一致,向有3個(gè)神鉛李int的切片中添加2個(gè)int,容量增長(zhǎng)為6。

需要注意的是, append 對(duì)切片擴(kuò)容時(shí),如果容量超過了一定范圍,處理策略又會(huì)有所不同??梢钥纯聪旅孢@個(gè)例子。

具體為什么會(huì)是這樣的變化過程,還需要從 源碼 中尋找答案。下面是 src/runtime/slice.go 中的 growslice 函數(shù)中的核心部分。

GoLang中的切片擴(kuò)容機(jī)制,與切片的數(shù)據(jù)類型、原本切片的容量、所需要的容量都有關(guān)系,比較復(fù)雜。對(duì)于常見數(shù)據(jù)類型,在元素?cái)?shù)量較少時(shí),大致可以認(rèn)為擴(kuò)容是按照翻倍進(jìn)行的。但具體情況需要具體分析。

Go切片數(shù)組深度解析

Go 中的分片數(shù)組,實(shí)際上有點(diǎn)類似于Java中的ArrayList,是一個(gè)可以擴(kuò)展的數(shù)組,但是Go中的切片由比較靈活,它和數(shù)組很像,也是基于數(shù)組,所以在了解Go切片前我們先了解下數(shù)組。

數(shù)組簡(jiǎn)單描述就由相同類型元素組成的數(shù)據(jù)結(jié)構(gòu), 在創(chuàng)建初期就確定了長(zhǎng)度,是不可變的。

但是Go的數(shù)組類型又和C與Java的數(shù)組類型不一樣, NewArray 用于創(chuàng)建一個(gè)數(shù)組,從源碼中可以看出最后返回的是 Array{}的指針,并不是第一個(gè)元素的指針,在Go中數(shù)組屬于值類型,在進(jìn)行傳遞時(shí),采取的是值傳遞,通過拷貝整個(gè)數(shù)組。Go語言的數(shù)組是一種有序的struct。

Go 語言的數(shù)組有兩種不同的創(chuàng)建方式,一種是顯示的初始化,一種是隱式的初始化。

注意一定是使用 [...]T 進(jìn)行創(chuàng)建,使用三個(gè)點(diǎn)的隱式創(chuàng)建,編譯器會(huì)對(duì)數(shù)組的大小進(jìn)行推導(dǎo),只是Go提供的一種語法糖。

其次,Go中數(shù)組的類型,是由數(shù)值類型和長(zhǎng)度兩個(gè)一起確定的。[2]int 和 [3]int 不是同一個(gè)類型,不能進(jìn)行傳參和比較,把數(shù)組理解為類型和長(zhǎng)度兩個(gè)屬性的結(jié)構(gòu)體,其實(shí)就一目了然了。

Go中的數(shù)組屬于值類型,通常應(yīng)該存儲(chǔ)于棧中,局部變量依然會(huì)根據(jù)逃逸分析確定存儲(chǔ)棧還是堆中。

編譯器對(duì)數(shù)組函數(shù)中做兩種不同的優(yōu)化:

在靜態(tài)區(qū)完成賦值后復(fù)制到棧中。

總結(jié)起來,在不考慮逃逸分析的情況下,如果數(shù)組中元素的個(gè)數(shù)小于或者等于 4 個(gè),那么所有的變量會(huì)直接在棧上初始化,如果數(shù)組元素大于 4 個(gè),變量就會(huì)在靜態(tài)存儲(chǔ)區(qū)初始化然后拷貝到棧上。

由于數(shù)組是值類型,那么賦值和函數(shù)傳參操作都會(huì)復(fù)制整個(gè)數(shù)組數(shù)據(jù)。

不管是賦值或函數(shù)傳參,地址都不一致,發(fā)生了拷貝。如果數(shù)組的數(shù)據(jù)較大,則會(huì)消耗掉大量?jī)?nèi)存。那么為了減少拷貝我們可以主動(dòng)的傳遞指針呀。

地址是一樣的,不過傳指針會(huì)有一個(gè)弊端,從打印結(jié)果可以看到,指針地址都是同一個(gè),萬一原數(shù)組的指針指向更改手腔了,那么函數(shù)里面的指針指向都會(huì)跟空亂著更改。斗薯檔

同樣的我們將數(shù)組轉(zhuǎn)換為切片,通過傳遞切片,地址是不一樣的,數(shù)組值相同。

切片是引用傳遞,所以它們不需要使用額外的內(nèi)存并且比使用數(shù)組更有效率。

所以,切片屬于引用類型。

通過這種方式可以將數(shù)組轉(zhuǎn)換為切片。

中間不加三個(gè)點(diǎn)就是切片,使用這種方式創(chuàng)建切片,實(shí)際上是先創(chuàng)建數(shù)組,然后再通過第一種方式創(chuàng)建。

使用make創(chuàng)建切片,就不光編譯期了,make創(chuàng)建切片會(huì)涉及到運(yùn)行期。1. 切片的大小和容量是否足夠?。?/p>

切片是否發(fā)生了逃逸,最終在堆上初始化。如果切片小的話會(huì)先在?;蜢o態(tài)區(qū)進(jìn)行創(chuàng)建。

切片有一個(gè)數(shù)組的指針,len是指切片的長(zhǎng)度, cap指的是切片的容量。

cap是在初始化切片是生成的容量。

發(fā)現(xiàn)切片的結(jié)構(gòu)體是數(shù)組的地址指針array unsafe.Pointer,而Go中數(shù)組的地址代表數(shù)組結(jié)構(gòu)體的地址。

slice 中得到一塊內(nèi)存地址,array[0]或者unsafe.Pointer(array[0])。

也可以通過地址構(gòu)造切片

nil切片:指的unsafe.Pointer 為nil

空切片:

創(chuàng)建的指針不為空,len和cap為空

當(dāng)一個(gè)切片的容量滿了,就需要擴(kuò)容了。怎么擴(kuò),策略是什么?

如果原來數(shù)組切片的容量已經(jīng)達(dá)到了最大值,再想擴(kuò)容, Go 默認(rèn)會(huì)先開一片內(nèi)存區(qū)域,把原來的值拷貝過來,然后再執(zhí)行 append() 操作。這種情況對(duì)現(xiàn)數(shù)組的地址和原數(shù)組地址不相同。

從上面結(jié)果我們可以看到,如果用 range 的方式去遍歷一個(gè)切片,拿到的 Value 其實(shí)是切片里面的值拷貝,即淺拷貝。所以每次打印 Value 的地址都不變。

由于 Value 是值拷貝的,并非引用傳遞,所以直接改 Value 是達(dá)不到更改原切片值的目的的,需要通過 slice[index] 獲取真實(shí)的地址。

golang 匿名結(jié)構(gòu)體怎么append?

使用下標(biāo)侍粗引用,只適合修改已知數(shù)組大小的情況老睜鎮(zhèn)。如果早悉還沒有開辟空間去引用,將會(huì)引起越界。所以需要你額外再定義一次匿名結(jié)構(gòu)體。

strArr:=[]string{"a","b","c","d"}

var school School

school.SchoolName="北京大學(xué)"

for i:=0;ilen(strArr) ;i++ {

temp:= struct {

ClassId int

ClassName string

}{i,strArr[i]}

school.Class=append(school.Class,temp)

}

fmt.Println(school)


當(dāng)前標(biāo)題:go語言append源碼 go語言示例
文章轉(zhuǎn)載:http://weahome.cn/article/ddpgjce.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部