簡單介紹Go 語言常見的一些坑
For迴圈在我們日常編碼中可能用的很多。在很多業務場景中我們都需要用for迴圈處理。但golang中的for迴圈在使用上需要注意一些問題,大家可否遇到。先看下邊這一段程式碼:
func testSlice() { a := []int64{1,2,3} for _, v := range a { go func() { fmt.Println(v) }() } time.Sleep(time.Second) } output: 3 3 3
那麼為什麼會輸出的是這個結果呢?
在golang的for迴圈中,迴圈內部建立的函式變數都是共享同一塊記憶體地址,for迴圈總是使用同一塊記憶體去接收迴圈中的的value變數的值。不管迴圈多少次,value的記憶體地址都是相同的。我們可以測試一下:
func testSliceWithAddress() { a := []int64{1,2,3} for _, v := range a { go func() { fmt.Println(&v) }() } time.Sleep(time.Second) } output: 0xc0000b2008 0xc0000b2008 0xc0000b2008
符合預期。如果大家比較感興趣的話可以去將這段程式碼的彙編列印出來,就可以發現迴圈的v一直在操作同一塊記憶體。
同樣的,在slice迴圈這塊我們還會遇見另一個有趣的地方,大家可以看看下邊這段程式碼輸出什麼?
func testRange3() { a := []int64{1,2,3} for _, v := range a { a = append(a, v) } fmt.Println(a) }
這段程式碼的輸出結果是:[1 2 3 1 2 3],為什麼呢?因為golang在迴圈前會先複製一個a,然後對新複製的a進行操作,所以迴圈的次數不會隨著append而增多。
比如返回了一個空指標,但並不是一個空interface
func testInterface() { doit := func(arg int) interface{} { var result * struct{} = nil if arg > 0 { result = &struct{}{} } return result } if res := doit(-1); res != nil { fmt.Println("result:", res) } }
輸出結果為:result: ,為什麼呢?因為在go裡邊變數有型別和值兩個屬性,在比較的時候也會比較型別和值都相同才會認為相等。程式碼中result的型別是指標,值是nil,所以會有這樣的輸出。
當引數的可變引數是空介面型別時,傳入空介面的切片時需要注意引數展開的問題。
func testVolatile() { var a = []interface{}{1, 2, 3} fmt.Println(a) fmt.Println(a...) } 輸出結果為: [1 2 3] 1 2 3
map遍歷時順序不固定
不要相信map的順序!
func testMap() { m := map[string]string{ "a": "a", "b": "b", "c": "c", } for k, v := range m { println(k, v) } }
具體原因大家可以看一下原始碼:map.go:mapiterinit,就會發現下邊這個程式碼用來決定從哪開始遍歷map。另一個原因是map 在某些特定情況下(例如擴容),會發生key的搬遷重組。而遍歷的過程,就是按順序遍歷bucket,同時按順序遍歷bucket中的key。搬遷後,key的位置發生了重大的變化,所以遍歷map的結果就不可能按原來的順序了。
func mapiterinit(t *maptype, h *hmap, it *hiter) { ...... // decide where to start r := uintptr(fastrand()) ...... }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2840988/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 簡單介紹Go 語言單例模式Go單例模式
- 簡單介紹Go語言常用的打log方式Go
- 【面試篇】Go語言常見踩坑(一)面試Go
- C語言-GCC的簡單介紹C語言GC
- Go語言介紹Go
- groovy 程式語言簡單介紹
- 關於C語言的簡單介紹C語言
- Go 語言簡介(上)— 語法Go
- Go語言的”坑“Go
- go語言初學者常見錯誤Go
- Go語言的那些坑Go
- javascript函數語言程式設計簡單介紹JavaScript函數程式設計
- Go語言學習(1) - 簡介Go
- Go語言工具簡介 - HoneybadgerGo
- GO語言一個簡單的工程Go
- 一些常見的簡單最佳化
- Kotlin語言極簡介紹Kotlin
- go語言簡單入門--常識和資料型別Go資料型別
- go語言的31個坑Go
- 一些重要 Docker 命令的簡單介紹Docker
- Go 語言的網路程式設計簡介Go程式設計
- 常見預訓練語言模型簡述模型
- JavaScript return語句簡單介紹JavaScript
- javascript with()語句用法簡單介紹JavaScript
- Go語言中defer的一些坑Go
- Go語言詳細介紹:logo和版本Go
- Go 語言開源 CI/CD 容器 Drone 介紹Go
- fx 簡單介紹 [Go Hack 2017]Go
- 簡單介紹常見的三種架構設計模式及其優缺點!架構設計模式
- Web前端工程師的一些常見誤區介紹!Web前端工程師
- Snow——簡單易用的 Go 語言業務框架Go框架
- 兄弟連golang神技(1)-關於 Go 語言的介紹Golang
- 簡單介紹Go 字串比較的實現示例Go字串
- setTimeout()函式延遲迴圈語句的異常簡單介紹函式
- zTree外掛常鍵用法簡單介紹
- 四款常見IT自動化運維工具簡單介紹-行雲管家運維
- 使用Go語言實現簡單MapReduce框架Go框架
- Go 語言關於 Type Assertions 的 坑Go