控制 Golang 切片的增長

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

如果你是Golang 新手,並對它的數組(切片)不太瞭解,你可能想從這裡開始this introduction。

如今,當我們談論數組時,開發人員可能會談論數組的兩種行為之一:一種是靜態(或稱為固定數組),另一種是動態。靜態數組的固定長度在定義的時候被初始化完成。動態數組(一般地)用一個靜態數組定義,但是當需要的時候,能夠增長其長度。那麼這是如何?呢?當你要在動態數組中添加一項條目時,如果數組下面的固定長度已經滿了,它會建立一個更大的數組並且將資料拷併到並覆蓋更大的數組中。

這種增長和拷貝可能似乎及其地慢,但是動態數組通常使用一種動態分配多餘空間的增長演算法。這種簡單的演算法將會增加原來數組的一倍大小。所以當我們試圖插入在一個容量為10的數組中插入第11條條目時,我們最終會得到一個新數組容量為20,內容包含11條值。

刺蝟bear
翻譯於 3個月前

1人頂

頂 翻譯的不錯哦!

雖然這有助於避免過度複製,但是它也被嚴格限制在記憶體中。想象插入 750 000 條記錄到一個數組,一開始它的容量是10。 首先,你必須做18次分配(10, 20, 40, 80 ...)。每一個都不得不被垃圾收集器收集並導致片段。此外,最終你會得到一個數組,可以容納 560720 個額外的值(... 327 680, 655 360, 1 310 720)。由於這些原因,只要有可能,最好是初始化動態數組使之有一個合理的尺寸。實際上,你只能估計一個粗略的尺寸,最好是超過一些(它會更少地分配,並最終使用更少的記憶體)。

數組的大小是固定的,但是由於內建 append 方法,我們獲得了動態行為。事實上 append 會返回一個對象,並強調了這樣一個事實,在必要時將會建立。增長演算法 append 使用的是存在容量的兩倍。

無若
翻譯於 3個月前

0人頂

頂 翻譯的不錯哦!

如果我們想要一個不同的行為呢?例如,如果我們想增長一個固定大小的數組呢?或者,如果我們想要在數組中的任意位置上插入一個數值,類似動態行為呢?在任何位置都可以插入資料的簡單的解決方案是重新建立一個新的陣列:

func insert(original []int, position int, value int) []int {  //we'll grow by 1  target := make([]int, len(original)+1)  //copy everything up to the position  copy(target, original[:position])  //set the new value at the desired position  target[position] = value  //copy everything left over  copy(target[position+1:], original[position:])  return target}

這當然意味著我們不再獲得記憶體上的效能優勢(每一個插入都需要一個新的數組來建立)。要解決這個問題,我們需要瞭解切片,容量和長度,以及它們與數組的關係。以下代碼的輸出是什麼呢?

x := make([]int, 4)x = append(x, 5)fmt.Println(x)

它可以很容易地看上面的代碼,並認為我們會寫入索引0,從而獲得[ 5,0,0,0 ]。但是,上面的代碼建立一個基本數組,一個容量為4和一個長度為4的片。當我們append時,我們總是增加切片的長度(如果必要的話,增加數組的容量(通過建立一個新的數組))。上述的結果:[ 0,0,0,0,5 ]。考慮一個更明顯的例子:

x := []int{1, 2, 3, 4}x = append(x, 5)fmt.Println(x)

我們可以肯定輸出是[ 1,2,3,4,5 ]。建立一個“空”的切片,然後預分配指定的長度(數組的長度)和切片的容量的底層數組:

x := make([]int, 0, 4)x = append(x, 5)fmt.Println(x)//prints [5]
sheepbao
翻譯於 2個月前

0人頂

頂 翻譯的不錯哦!

上述代碼中一個有趣的問題是:append返回的是什嗎?第一種情況:當 len(x) == cap(x)(切片長度等於切片容量)時,將建立一個新的數組,並返回一個新的切片引用。第二種情況:切片長度為0,但容量為4,不會建立一個新的的數組。

(譯者註:原文中第二種情況為:In the second case, where len(x) == 4 but cap(x) == 0 是錯的。在Go中 len(x) <= cap(x))

理解了嗎?讓我們再做個測試,下列代碼的輸出是什麼:

original := []int{1,2,3,4} //a slice with a len and cap of 4other := originalother[2] = 8fmt.Println(original)fmt.Println(other)other = append(original, 5)other[2] = 9fmt.Println(original)fmt.Println(other)

第一段代碼的輸出是: [1, 2, 8, 4]。第二段代碼的輸出是: [1, 2, 8, 4]和[1, 2, 9, 4, 5]。與第一段輸出不同,是因為:append操作需要增加底層數組的長度,所以other被指定到一個新的切片上,而original沒變。

基於這些認知,我們可以我們自己的基於切片和數組的,有更高控制力的,類似append的插入函數了。我們的函數可以處理兩種情況:已達到最大容量(需要增加底層數組長度)、未達到最大容量。首先,我們看看達到最大容量時,如何處理:

func insert(original []int, position int, value int) []int {    l := len(original)    var target []int    if cap(original) == l {        target = make([]int, l+1, l+10)        copy(target, original[:position])        target[position] = value        copy(target[position+1:], original[position:])    } else {        // todo    }    return target}
caotj72
翻譯於 2個月前

0人頂

頂 翻譯的不錯哦!

可以看到,與我們前面實現的簡單複製類似。主要區別是:每次長度加10(可以根據你自己的需要調整),而不是增加1。

現在處理第二種情況,未達到最大容量:

    if cap(original) == l {        //see above    } else {        target = append(original, -1)        copy(target[position+1:], original[position:])        target[position] = value    }    return target}

上面這段代碼的關鍵是:我們用append追加了一個臨時值(-1)到切片。我們知道則不會建立一個新的數組(應為if語句,每次增加10個)。然後,將插入位置右側的值後移,並最終插入新值。

最後,我們對代碼進行重構,使其更緊湊一些:

func insert(original []int, position int, value int) []int {    l := len(original)    target := original    if cap(original) == l {        target = make([]int, l+1, l+10)        copy(target, original[:position])    } else {        target = append(target, -1)    }    copy(target[position+1:], original[position:])    target[position] = value    return target}
caotj72
翻譯於 2個月前

0人頂

頂 翻譯的不錯哦!

本文中的所有譯文僅用於學習和交流目的,轉載請務必註明文章譯者、出處、和本文連結
我們的翻譯工作遵照 CC 協議,如果我們的工作有侵犯到您的權益,請及時聯絡我們

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.