Go 中不定長度集合

來源:互聯網
上載者:User
如果你在使用像 C# 或 Java 這樣的程式設計語言後來到 go,你發現的第一件事就是沒有像 `List` 和 `Dictionary` 這樣的傳統集合類型。 這真讓我困惑了好幾個月。 我找到了一個名為 `container/list` 的軟體包,並且幾乎用它做所有的東西。我腦後一直有一個聲音在嘮叨。語言設計者不應該不直接支援對未知長度的集合管理的功能。每個人都在討論切片是如何在語言中被廣泛使用,但我只是在有明確定義的容量或者它們通過函數返回時我才使用切片,這有點不對勁!!因此,我在本月早些時候寫了一篇文章,揭開了切片的蓋子,希望能找到一些我不知道的魔法。我現在知道切片是如何工作的,但最終我仍然需要一個不斷進行長度增長的數組。我在學校學過,使用鏈表更有效率,是儲存大量資料更好的方法。特別是當你需要的集合長度未知時。這對我來說很有意義。當我思考使用一個空切片時,我頭腦中有一張非常**錯誤**的圖片:![slice-copy](https://raw.githubusercontent.com/studygolang/gctt-images/master/Collections-Of-Unknown-Length-in-Go/slice-copy.png)我一直在想 go 是如何建立大量新的切片值和底層數組做大量記憶體配置,並且不斷進行複製值。然後記憶體回收行程會因為所有這些小變數被建立和銷毀而過度工作。我無法想象需要做數千次這種操作。其實有更好的方法或更效率的方式我沒有意識到。在研究並提出了很多問題之後,我得出的結論是,在大多數實際情況下,使用切片比使用鏈表更好。這就是為什麼語言設計者花時間使切片儘可能生產力,並且沒有引入集合類型的原因。我們可以連續幾天討論各種邊界情況和效能問題,但 go 希望我們使用切片。因此切片應該是我們的首選,除非代碼告訴我們存在問題。掌握切片就像學國際象棋遊戲,易於學習但需要一輩子才能成為大師。因為底層數組可以共用,所以在使用中需要注意一些問題。在繼續閱讀之前,你最好看一下我的另一篇文章 [Understanding Slices in Go Programming](http://www.goinggo.net/2013/08/understanding-slices-in-go-programming.html)。本文的其餘部分將解釋如何使用切片處理未知容量的問題以及切片的運行機制。以下是使用空切片來管理未知長度集合的樣本:```gopackage mainimport ( "fmt" "math/rand" "time")type Record struct { ID int Name string Color string}func main() { // Let’s keep things unknown random := rand.New(rand.NewSource(time.Now().Unix())) // Create a large slice pretending we retrieved data // from a database data := make([]Record, 1000) // Create the data set for record := 0; record < 1000; record++ { pick := random.Intn(10) color := "Red" if pick == 2 { color = "Blue" } data[record] = Record{ ID: record, Name: fmt.Sprintf("Rec: %d", record), Color: color, } } // Split the records by color var red []Record var blue []Record for _, record := range data { if record.Color == "Red" { red = append(red, record) } else { blue = append(blue, record) } } // Display the counts fmt.Printf("Red[%d] Blue[%d]\n", len(red), len(blue))}```當我們運行這個程式時,由於隨機數產生器,我們將得到不同長度的紅色和藍色切片。我們無法提前知道紅色或藍色切片的容量需要,這對我來說是一種典型的情況。讓我們分解出代碼中更重要的部分:這兩行代碼建立了空切片。```govar red []Recordvar blue []Record```一個空切片長度和容量都是0,並且不存在底層數組。我們可以使用內建的 `append` 函數向切片中增加資料。```gored = append(red, record)blue = append(blue, record)````append` 函數功能非常酷,為我們做了很多東西。Kevin Gillette 在我的小組討論中進行了說明:(https://groups.google.com/forum/#!topic/golang-nuts/nXYuMX55b6c)在 go 語音規範中規定,前幾千個元素在容量增長的時候每次都將容量翻倍,然後以~1.25的速率進行容量增長。我不是學者,但我看到使用波浪號(~)相當多。有些人也許不知道這是什麼意思,這裡表示大約。因此,`append` 函數會增加底層數組的容量並為未來的增長預留空間。最終 `append` 函數將大約以1.25或25%的係數進行容量增長。讓我們證明 `append` 函數增長容量並高效運行:```gopackage mainimport ( "fmt" "reflect" "unsafe")func main() { var data []string for record := 0; record < 1050; record++ { data = append(data, fmt.Sprintf("Rec: %d", record)) if record < 10 || record == 256 || record == 512 || record == 1024 { sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&data))) fmt.Printf("Index[%d] Len[%d] Cap[%d]\n", record, sliceHeader.Len, sliceHeader.Cap) } }}```輸出結果:```Index[0] Len[1] Cap[1]Index[1] Len[2] Cap[2]Index[2] Len[3] Cap[4] - Ran Out Of Room, Double CapacityIndex[3] Len[4] Cap[4]Index[4] Len[5] Cap[8] - Ran Out Of Room, Double CapacityIndex[5] Len[6] Cap[8]Index[6] Len[7] Cap[8]Index[7] Len[8] Cap[8]Index[8] Len[9] Cap[16] - Ran Out Of Room, Double CapacityIndex[9] Len[10] Cap[16]Index[256] Len[257] Cap[512] - Ran Out Of Room, Double CapacityIndex[512] Len[513] Cap[1024] - Ran Out Of Room, Double CapacityIndex[1024] Len[1025] Cap[1280] - Ran Out Of Room, Grow by a factor of 1.25```如果我們觀察容量值,我們可以看到 Kevin 是絕對正確的。容量正如他所說的那樣在增長。在前1千的元素中,容量增加了一倍。然後容量以1.25或25%的係數增長。這意味著以這種方式使用切片將滿足我們在大多數情況下所需的效能,並且記憶體不會成為問題。最初我認為會為每次調用 `append` 時都會建立一個新的切片值,但事實並非如此。當我們調用 `append` 時,在棧中複製了 `red` 副本。然後當 `append` 返回時,會再進行一次複製操作,但使用的我們已有的記憶體。```gored = append(red, record)```在這種情況下,垃圾收集器沒有工作,所以我們根本沒有效能或記憶體問題。我的 C# 和參考型別的思想再次打擊了我。請坐好,因為下一個版本中的切片會有變化。Dominik Honnef 建立了一個部落格,用簡明的英文(謝謝)解釋了 Go tip 中正在編寫的內容。這些是下一版本中的內容。這是他部落格的和部落格中關於切片部分的連結。這是一篇很棒部落格,推薦閱讀。http://dominik.honnef.co/go-tip/http://dominik.honnef.co/go-tip/2013-08-23/#slicing你可以用切片做很多的事情,甚至可以寫一整本關於這個主題的書。就像我之前說的那樣,切片就像國際象棋一樣,易於學習但需要一輩子才能成為大師。如果您來自其他語言,如 C# 和 Java,那麼請擁抱切片並使用它。這正是 go 中正確的方式。

via: https://www.ardanlabs.com/blog/2013/08/collections-of-unknown-length-in-go.html

作者:William Kennedy 譯者:althen 校對:polaris1119

本文由 GCTT 原創編譯,Go語言中文網 榮譽推出

本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽

186 次點擊  
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.