欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

go語言append go語言append函數(shù)追加元素允許重復(fù)

go語言循環(huán)隊(duì)列的實(shí)現(xiàn)

隊(duì)列的概念在 順序隊(duì)列 中,而使用循環(huán)隊(duì)列的目的主要是規(guī)避假溢出造成的空間浪費(fèi),在使用循環(huán)隊(duì)列處理假溢出時(shí),主要有三種解決方案

成都創(chuàng)新互聯(lián)自2013年起,先為莊浪等服務(wù)建站,莊浪等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為莊浪企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

本文提供后兩種解決方案。

順序隊(duì)和循環(huán)隊(duì)列是一種特殊的線性表,與順序棧類似,都是使用一組地址連續(xù)的存儲(chǔ)單元依次存放自隊(duì)頭到隊(duì)尾的數(shù)據(jù)元素,同時(shí)附設(shè)隊(duì)頭(front)和隊(duì)尾(rear)兩個(gè)指針,但我們要明白一點(diǎn),這個(gè)指針并不是指針變量,而是用來表示數(shù)組當(dāng)中元素下標(biāo)的位置。

本文使用切片來完成的循環(huán)隊(duì)列,由于一開始使用三個(gè)參數(shù)的make關(guān)鍵字創(chuàng)建切片,在輸出的結(jié)果中不包含nil值(看起來很舒服),而且在驗(yàn)證的過程中發(fā)現(xiàn)使用append()函數(shù)時(shí)切片內(nèi)置的cap會(huì)發(fā)生變化,在消除了種種障礙后得到了一個(gè)四不像的循環(huán)隊(duì)列,即設(shè)置的指針是順序隊(duì)列的指針,但實(shí)際上進(jìn)行的操作是順序隊(duì)列的操作。最后是對(duì)make()函數(shù)和append()函數(shù)的一些使用體驗(yàn)和小結(jié),隊(duì)列的應(yīng)用放在鏈隊(duì)好了。

官方描述(片段)

即切片是一個(gè)抽象層,底層是對(duì)數(shù)組的引用。

當(dāng)我們使用

構(gòu)建出來的切片的每個(gè)位置的值都被賦為interface類型的初始值nil,但是nil值也是有大小的。

而使用

來進(jìn)行初始化時(shí),雖然生成的切片中不包含nil值,但是無法通過設(shè)置的指針變量來完成入隊(duì)和出隊(duì)的操作,只能使用append()函數(shù)來進(jìn)行操作

在go語言中,切片是一片連續(xù)的內(nèi)存空間加上長度與容量的標(biāo)識(shí),比數(shù)組更為常用。使用 append 關(guān)鍵字向切片中追加元素也是常見的切片操作

正是基于此,在使用go語言完成循環(huán)隊(duì)列時(shí),首先想到的就是使用make(type, len, cap)關(guān)鍵字方式完成切片初始化,然后使用append()函數(shù)來操作該切片,但這一方式出現(xiàn)了很多問題。在使用append()函數(shù)時(shí),切片的cap可能會(huì)發(fā)生變化,用不好就會(huì)發(fā)生擴(kuò)容或收縮。最終造成的結(jié)果是一個(gè)四不像的結(jié)果,入隊(duì)和出隊(duì)操作變得與指針變量無關(guān),失去了作為循環(huán)隊(duì)列的意義,用在順序隊(duì)列還算合適。

參考博客:

Go語言中的Nil

Golang之nil

Go 語言設(shè)計(jì)與實(shí)現(xiàn)

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

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

數(shù)組簡單描述就由相同類型元素組成的數(shù)據(jù)結(jié)構(gòu), 在創(chuà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ù)值類型和長度兩個(gè)一起確定的。[2]int 和 [3]int 不是同一個(gè)類型,不能進(jìn)行傳參和比較,把數(shù)組理解為類型和長度兩個(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ì)消耗掉大量內(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. 切片的大小和容量是否足夠小;

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

切片有一個(gè)數(shù)組的指針,len是指切片的長度, 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í)的地址。

如何看待go語言泛型的最新設(shè)計(jì)?

Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成為現(xiàn)實(shí)。Go 團(tuán)隊(duì)實(shí)施了一個(gè)看起來比較穩(wěn)定的設(shè)計(jì)草案,并且正以源到源翻譯器原型的形式獲得關(guān)注。本文講述的是泛型的最新設(shè)計(jì),以及如何自己嘗試泛型。

例子

FIFO Stack

假設(shè)你要?jiǎng)?chuàng)建一個(gè)先進(jìn)先出堆棧。沒有泛型,你可能會(huì)這樣實(shí)現(xiàn):

type?Stack?[]interface{}func?(s?Stack)?Peek()?interface{}?{

return?s[len(s)-1]

}

func?(s?*Stack)?Pop()?{

*s?=?(*s)[:

len(*s)-1]

}

func?(s?*Stack)?Push(value?interface{})?{

*s?=?

append(*s,?value)

}

但是,這里存在一個(gè)問題:每當(dāng)你 Peek 項(xiàng)時(shí),都必須使用類型斷言將其從 interface{} 轉(zhuǎn)換為你需要的類型。如果你的堆棧是 *MyObject 的堆棧,則意味著很多 s.Peek().(*MyObject)這樣的代碼。這不僅讓人眼花繚亂,而且還可能引發(fā)錯(cuò)誤。比如忘記 * 怎么辦?或者如果您輸入錯(cuò)誤的類型怎么辦?s.Push(MyObject{})` 可以順利編譯,而且你可能不會(huì)發(fā)現(xiàn)到自己的錯(cuò)誤,直到它影響到你的整個(gè)服務(wù)為止。

通常,使用 interface{} 是相對(duì)危險(xiǎn)的。使用更多受限制的類型總是更安全,因?yàn)榭梢栽诰幾g時(shí)而不是運(yùn)行時(shí)發(fā)現(xiàn)問題。

泛型通過允許類型具有類型參數(shù)來解決此問題:

type?Stack(type?T)?[]Tfunc?(s?Stack(T))?Peek()?T?{

return?s[len(s)-1]

}

func?(s?*Stack(T))?Pop()?{

*s?=?(*s)[:

len(*s)-1]

}

func?(s?*Stack(T))?Push(value?T)?{

*s?=?

append(*s,?value)

}

這會(huì)向 Stack 添加一個(gè)類型參數(shù),從而完全不需要 interface{}。現(xiàn)在,當(dāng)你使用 Peek() 時(shí),返回的值已經(jīng)是原始類型,并且沒有機(jī)會(huì)返回錯(cuò)誤的值類型。這種方式更安全,更容易使用。(譯注:就是看起來更丑陋,^-^)

此外,泛型代碼通常更易于編譯器優(yōu)化,從而獲得更好的性能(以二進(jìn)制大小為代價(jià))。如果我們對(duì)上面的非泛型代碼和泛型代碼進(jìn)行基準(zhǔn)測(cè)試,我們可以看到區(qū)別:

type?MyObject?struct?{

X?

int

}

var?sink?MyObjectfunc?BenchmarkGo1(b?*testing.B)?{

for?i?:=?0;?i??b.N;?i++?{

var?s?Stack

s.Push(MyObject{})

s.Push(MyObject{})

s.Pop()

sink?=?s.Peek().(MyObject)

}

}

func?BenchmarkGo2(b?*testing.B)?{

for?i?:=?0;?i??b.N;?i++?{

var?s?Stack(MyObject)

s.Push(MyObject{})

s.Push(MyObject{})

s.Pop()

sink?=?s.Peek()

}

}

結(jié)果:

BenchmarkGo1BenchmarkGo1-16?????12837528?????????87.0?ns/op???????48?B/op????????2?allocs/opBenchmarkGo2BenchmarkGo2-16?????28406479?????????41.9?ns/op???????24?B/op????????2?allocs/op

在這種情況下,我們分配更少的內(nèi)存,同時(shí)泛型的速度是非泛型的兩倍。

合約(Contracts)

上面的堆棧示例適用于任何類型。但是,在許多情況下,你需要編寫僅適用于具有某些特征的類型的代碼。例如,你可能希望堆棧要求類型實(shí)現(xiàn) String() 函數(shù)

網(wǎng)站欄目:go語言append go語言append函數(shù)追加元素允許重復(fù)
標(biāo)題來源:http://chinadenli.net/article16/doddedg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)軟件開發(fā)品牌網(wǎng)站設(shè)計(jì)外貿(mào)建站網(wǎng)站收錄全網(wǎng)營銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)