亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

Golang中切片的用法與本質詳解

2020-04-01 18:56:02
字體:
來源:轉載
供稿:網友

前言

Go 數組的長度不可改變,在特定場景中這樣的集合就不太適用,Go中提供了一種靈活,功能強悍的內置類型切片("動態數組"),與數組相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大

Go的切片類型為處理同類型數據序列提供一個方便而高效的方式。 切片有些類似于其他語言中的數組,但是有一些不同尋常的特性。 本文將深入切片的本質,并講解它的用法。

數組

Go的切片是在數組之上的抽象數據類型,因此在了解切片之前必須要先理解數組。

數組類型定義了長度和元素類型。例如, [4]int 類型表示一個四個整數的數組。 數組的長度是固定的,長度是數組類型的一部分(  [4]int 和  [5]int 是完全不同的類型)。 數組可以以常規的索引方式訪問,表達式  s[n] 訪問數組的第 n 個元素。

var a [4]inta[0] = 1i := a[0]// i == 1

數組不需要顯式的初始化;數組的零值是可以直接使用的,數組元素會自動初始化為其對應類型的零值:

// a[2] == 0, int 類型的零值

類型 [4]int 對應內存中四個連續的整數:

Golang,切片,用法,本質

Go的數組是值語義。一個數組變量表示整個數組,它不是指向第一個元素的指針(不像 C 語言的數組)。 當一個數組變量被賦值或者被傳遞的時候,實際上會復制整個數組。 (為了避免復制數組,你可以傳遞一個指向數組的指針,但是數組指針并不是數組。) 可以將數組看作一個特殊的struct,結構的字段名對應數組的索引,同時成員的數目固定。

數組的字面值像這樣:

b := [2]string{"Penn", "Teller"}

當然,也可以讓編譯器統計數組字面值中元素的數目:

b := [...]string{"Penn", "Teller"}

這兩種寫法, b 都是對應  [2]string 類型。

切片

數組雖然有適用它們的地方,但是數組不夠靈活,因此在Go代碼中數組使用的并不多。 但是,切片則使用得相當廣泛。切片基于數組構建,但是提供更強的功能和便利。

切片類型的寫法是 []T ,  T 是切片元素的類型。和數組不同的是,切片類型并沒有給定固定的長度。

切片的字面值和數組字面值很像,不過切片沒有指定元素個數:

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

切片可以使用內置函數 make 創建,函數簽名為:

func make([]T, len, cap) []T

其中T代表被創建的切片元素的類型。函數 make 接受一個類型、一個長度和一個可選的容量參數。 調用  make 時,內部會分配一個數組,然后返回數組對應的切片。

var s []bytes = make([]byte, 5, 5)// s == []byte{0, 0, 0, 0, 0}

當容量參數被忽略時,它默認為指定的長度。下面是簡潔的寫法:

s := make([]byte, 5)

可以使用內置函數 len 和  cap 獲取切片的長度和容量信息。

len(s) == 5cap(s) == 5

接下來的兩個小節將討論長度和容量之間的關系。

切片的零值為 nil 。對于切片的零值,  len 和  cap 都將返回0。

切片也可以基于現有的切片或數組生成。切分的范圍由兩個由冒號分割的索引對應的半開區間指定。 例如,表達式 b[1:4] 創建的切片引用數組  b 的第1到3個元素空間(對應切片的索引為0到2)。

b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}// b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b

切片的開始和結束的索引都是可選的;它們分別默認為零和數組的長度。

// b[:2] == []byte{'g', 'o'}// b[2:] == []byte{'l', 'a', 'n', 'g'}// b[:] == b

下面語法也是基于數組創建一個切片:

x := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:] // a slice referencing the storage of x

切片的內幕

一個切片是一個數組片段的描述。它包含了指向數組的指針,片段的長度, 和容量(片段的最大長度)。

Golang,切片,用法,本質

前面使用 make([]byte, 5) 創建的切片變量  s 的結構如下:

Golang,切片,用法,本質

長度是切片引用的元素數目。容量是底層數組的元素數目(從切片指針開始)。 關于長度和容量和區域將在下一個例子說明。

我們繼續對 s 進行切片,觀察切片的數據結構和它引用的底層數組:

s = s[2:4]

Golang,切片,用法,本質

切片操作并不復制切片指向的元素。它創建一個新的切片并復用原來切片的底層數組。 這使得切片操作和數組索引一樣高效。因此,通過一個新切片修改元素會影響到原始切片的對應元素。

d := []byte{'r', 'o', 'a', 'd'}e := d[2:] // e == []byte{'a', 'd'}e[1] = 'm'// e == []byte{'a', 'm'}// d == []byte{'r', 'o', 'a', 'm'}

前面創建的切片 s 長度小于它的容量。我們可以增長切片的長度為它的容量:

s = s[:cap(s)]

Golang,切片,用法,本質

切片增長不能超出其容量。增長超出切片容量將會導致運行時異常,就像切片或數組的索引超 出范圍引起異常一樣。同樣,不能使用小于零的索引去訪問切片之前的元素。

切片的生長(copy and append 函數)

要增加切片的容量必須創建一個新的、更大容量的切片,然后將原有切片的內容復制到新的切片。 整個技術是一些支持動態數組語言的常見實現。下面的例子將切片 s 容量翻倍,先創建一個2倍 容量的新切片  t ,復制  s 的元素到  t ,然后將  t 賦值給  s :

t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0for i := range s {  t[i] = s[i]}s = t

循環中復制的操作可以由 copy 內置函數替代。copy 函數將源切片的元素復制到目的切片。 它返回復制元素的數目。

func copy(dst, src []T) int

copy 函數支持不同長度的切片之間的復制(它只復制較短切片的長度個元素)。 此外,  copy 函數可以正確處理源和目的切片有重疊的情況。

使用 copy 函數,我們可以簡化上面的代碼片段:

t := make([]byte, len(s), (cap(s)+1)*2)copy(t, s)s = t

一個常見的操作是將數據追加到切片的尾部。下面的函數將元素追加到切片尾部, 必要的話會增加切片的容量,最后返回更新的切片:

func AppendByte(slice []byte, data ...byte) []byte { m := len(slice) n := m + len(data) if n > cap(slice) { // if necessary, reallocate  // allocate double what's needed, for future growth.  newSlice := make([]byte, (n+1)*2)  copy(newSlice, slice)  slice = newSlice } slice = slice[0:n] copy(slice[m:n], data) return slice}

下面是 AppendByte 的一種用法:

p := []byte{2, 3, 5}p = AppendByte(p, 7, 11, 13)// p == []byte{2, 3, 5, 7, 11, 13}

類似 AppendByte 的函數比較實用,因為它提供了切片容量增長的完全控制。 根據程序的特點,可能希望分配較小的活較大的塊,或則是超過某個大小再分配。

但大多數程序不需要完全的控制,因此Go提供了一個內置函數 append , 用于大多數場合;它的函數簽名:

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

append 函數將  x 追加到切片  s 的末尾,并且在必要的時候增加容量。

a := make([]int, 1)// a == []int{0}a = append(a, 1, 2, 3)// a == []int{0, 1, 2, 3}

如果是要將一個切片追加到另一個切片尾部,需要使用 ... 語法將第2個參數展開為參數列表。

a := []string{"John", "Paul"}b := []string{"George", "Ringo", "Pete"}a = append(a, b...) // equivalent to "append(a, b[0], b[1], b[2])"// a == []string{"John", "Paul", "George", "Ringo", "Pete"}

由于切片的零值 nil 用起來就像一個長度為零的切片,我們可以聲明一個切片變量然后在循環 中向它追加數據:

// Filter returns a new slice holding only// the elements of s that satisfy f()func Filter(s []int, fn func(int) bool) []int { var p []int // == nil for _, v := range s {  if fn(v) {   p = append(p, v)  } } return p}

可能的“陷阱”

正如前面所說,切片操作并不會復制底層的數組。整個數組將被保存在內存中,直到它不再被引用。 有時候可能會因為一個小的內存引用導致保存所有的數據。

例如, FindDigits 函數加載整個文件到內存,然后搜索第一個連續的數字,最后結果以切片方式返回。

var digitRegexp = regexp.MustCompile("[0-9]+")func FindDigits(filename string) []byte { b, _ := ioutil.ReadFile(filename) return digitRegexp.Find(b)}

這段代碼的行為和描述類似,返回的 []byte 指向保存整個文件的數組。因為切片引用了原始的數組, 導致 GC 不能釋放數組的空間;只用到少數幾個字節卻導致整個文件的內容都一直保存在內存里。

要修復整個問題,可以將感興趣的數據復制到一個新的切片中:

func CopyDigits(filename string) []byte { b, _ := ioutil.ReadFile(filename) b = digitRegexp.Find(b) c := make([]byte, len(b)) copy(c, b) return c}

可以使用 append 實現一個更簡潔的版本。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人精品影院| 免费91麻豆精品国产自产在线观看| 欧美性高潮在线| 久久久人成影片一区二区三区观看| 久久久久久久影院| 91精品国产综合久久香蕉922| 国产一区二区三区三区在线观看| 2019国产精品自在线拍国产不卡| 欧洲永久精品大片ww免费漫画| 国产一区二区三区在线| 亚洲人成亚洲人成在线观看| 久久电影一区二区| 尤物yw午夜国产精品视频明星| 精品国产乱码久久久久久虫虫漫画| 久久久久久噜噜噜久久久精品| 亚洲成色777777在线观看影院| 91国产一区在线| 国产美女主播一区| 欧美激情成人在线视频| 久久精视频免费在线久久完整在线看| 国产大片精品免费永久看nba| 中文字幕精品网| 欧美精品aaa| 久久人人爽人人爽爽久久| 国产自摸综合网| 亚洲无限乱码一二三四麻| 欧美性猛交xxxx富婆弯腰| 国产mv久久久| 91精品国产综合久久久久久久久| 欧美午夜影院在线视频| 欧美激情xxxx| 久久99视频精品| 亚洲成人网在线观看| 国产精品成人一区二区| 主播福利视频一区| 国产精品第2页| 国产亚洲一区二区在线| 日韩中文字幕视频| 欧美在线视频网站| 欧美成人精品激情在线观看| 日韩精品极品视频免费观看| 亚洲视频日韩精品| 国产福利精品视频| 欧美激情一区二区三区在线视频观看| 日本免费一区二区三区视频观看| 91爱视频在线| 亚洲欧美在线磁力| yw.139尤物在线精品视频| 国外成人在线直播| 国产精品露脸av在线| 国产精品久久77777| 亚洲成人久久网| 欧美精品中文字幕一区| 国产一区二区三区视频在线观看| 国产精品99一区| 欧美最猛黑人xxxx黑人猛叫黄| 91精品国产综合久久久久久蜜臀| 欧美激情啊啊啊| 亚洲桃花岛网站| 欧美日韩中国免费专区在线看| 成人亚洲欧美一区二区三区| 日本欧美黄网站| 久久久97精品| 国产伊人精品在线| 亚洲成人性视频| 亚洲国产黄色片| 高清欧美性猛交xxxx黑人猛交| 欧美午夜视频在线观看| 欧美在线一级视频| 国产精品欧美激情| 欧美成人精品在线播放| 清纯唯美日韩制服另类| 日本视频久久久| 欧美成人免费网| 91精品久久久久久久久久久| 日本精品久久久久久久| 日本欧美爱爱爱| 精品亚洲国产视频| 亚洲欧美制服第一页| 91九色在线视频| 国产精品日韩在线| 中文字幕久热精品在线视频| 538国产精品一区二区在线| 国产精品自产拍在线观看中文| 国产精品91久久久久久| 91国产中文字幕| 日韩美女视频免费在线观看| 久久天天躁夜夜躁狠狠躁2022| 91在线视频成人| 7m精品福利视频导航| 久久免费视频观看| 久久久欧美一区二区| 亚洲欧洲黄色网| 欧美在线视频免费观看| 欧美国产视频日韩| 色偷偷av一区二区三区| 国产精品久久久久久一区二区| 国产精品99久久久久久www| 久久99精品久久久久久噜噜| 最近2019中文字幕mv免费看| 欧美一级片在线播放| 国产一区玩具在线观看| 久久精品欧美视频| 不卡在线观看电视剧完整版| 欧美激情videos| 美日韩精品视频免费看| 91免费人成网站在线观看18| 欧美一级淫片aaaaaaa视频| 97视频在线观看成人| 欧美夫妻性视频| 亚洲欧美制服中文字幕| 成人av色在线观看| 国产精品视频1区| 欧洲亚洲女同hd| 久久国产精品久久久久久| 在线视频免费一区二区| 91sao在线观看国产| 琪琪亚洲精品午夜在线| 亚洲国产精品成人精品| 欧美成人性色生活仑片| 国语自产精品视频在线看抢先版图片| 亚洲va欧美va国产综合剧情| 亚洲第一中文字幕| 日韩中文字幕网| 免费91在线视频| 亚洲精品一区中文字幕乱码| 欧美黑人又粗大| 亚洲精品资源在线| 亚洲天堂网站在线观看视频| 日韩在线不卡视频| 奇米成人av国产一区二区三区| 91人人爽人人爽人人精88v| 美女福利视频一区| 九九九久久久久久| 懂色av一区二区三区| 成人免费视频97| 国产精品最新在线观看| 久久天堂电影网| 97国产精品免费视频| 久久伊人免费视频| 久久综合九色九九| 国产精品亚发布| 欧美日韩一区二区三区| 欧美精品在线免费观看| 日韩亚洲精品视频| 久久久精品免费视频| 久久99热这里只有精品国产| 色婷婷综合久久久久中文字幕1| 91天堂在线观看| 久久伊人精品天天| 欧美精品一区在线播放| 国产精品第10页| 日韩av电影在线播放| 久久韩剧网电视剧| 91av视频在线免费观看| 亚洲精品在线91| 欧美性xxxx| 欧美视频在线视频| 午夜欧美不卡精品aaaaa| 中文字幕国产亚洲2019| 国产精品高清在线观看| 亚洲一区二区在线| 91麻豆国产语对白在线观看| 在线电影中文日韩|