自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go 語言常見踩坑記

開發(fā) 后端
For循環(huán)在我們日常編碼中可能用的很多。在很多業(yè)務場景中我們都需要用for循環(huán)處理。但golang中的for循環(huán)在使用上需要注意一些問題,大家可否遇到。

引言

本系列會列舉一些在Go面試中常見的問題。

切片循環(huán)問題

For循環(huán)在我們日常編碼中可能用的很多。在很多業(yè)務場景中我們都需要用for循環(huán)處理。但golang中的for循環(huán)在使用上需要注意一些問題,大家可否遇到。先看下邊這一段代碼:

  1. func testSlice() { 
  2.     a := []int64{1,2,3} 
  3.     for _, v := range a { 
  4.         go func() { 
  5.             fmt.Println(v) 
  6.         }() 
  7.     } 
  8.      
  9.     time.Sleep(time.Second
  10.  
  11. output: 3 3 3 

那么為什么會輸出的是這個結果呢?

在golang的for循環(huán)中,循環(huán)內部創(chuàng)建的函數變量都是共享同一塊內存地址,for循環(huán)總是使用同一塊內存去接收循環(huán)中的的value變量的值。不管循環(huán)多少次,value的內存地址都是相同的。我們可以測試一下:

  1. func testSliceWithAddress() { 
  2.     a := []int64{1,2,3} 
  3.     for _, v := range a { 
  4.         go func() { 
  5.             fmt.Println(&v) 
  6.         }() 
  7.  
  8.     } 
  9.  
  10.     time.Sleep(time.Second
  11.  
  12. output
  13.         0xc0000b2008 
  14.         0xc0000b2008 
  15.         0xc0000b2008 

符合預期。如果大家比較感興趣的話可以去將這段代碼的匯編打印出來,就可以發(fā)現(xiàn)循環(huán)的v一直在操作同一塊內存。

同樣的,在slice循環(huán)這塊我們還會遇見另一個有趣的地方,大家可以看看下邊這段代碼輸出什么?

  1. func testRange3() { 
  2.     a := []int64{1,2,3} 
  3.     for _, v := range a { 
  4.         a = append(a, v) 
  5.     } 
  6.  
  7.     fmt.Println(a) 

這段代碼的輸出結果是:[1 2 3 1 2 3],為什么呢?因為golang在循環(huán)前會先拷貝一個a,然后對新拷貝的a進行操作,所以循環(huán)的次數不會隨著append而增多。

interface和nil比較

比如返回了一個空指針,但并不是一個空interface

  1. func testInterface() { 
  2.     doit := func(arg int) interface{} { 
  3.         var result * struct{} = nil 
  4.         if arg > 0 { 
  5.             result = &struct{}{} 
  6.         } 
  7.  
  8.         return result 
  9.     } 
  10.  
  11.     if res := doit(-1); res != nil { 
  12.         fmt.Println("result:", res) 
  13.     } 

輸出結果為:result: ,為什么呢?因為在go里邊變量有類型和值兩個屬性,在比較的時候也會比較類型和值都相同才會認為相等。代碼中result的類型是指針,值是nil,所以會有這樣的輸出。

可變參數是空接口類型

當參數的可變參數是空接口類型時,傳入空接口的切片時需要注意參數展開的問題。

  1. func testVolatile() { 
  2.     var a = []interface{}{1, 2, 3} 
  3.  
  4.     fmt.Println(a) 
  5.     fmt.Println(a...) 

輸出結果為:

  1. [1 2 3] 
  2. 1 2 3 

map遍歷時順序不固定

不要相信map的順序!

  1. func testMap() { 
  2.     m := map[string]string{ 
  3.         "a""a"
  4.         "b""b"
  5.         "c""c"
  6.     } 
  7.  
  8.     for k, v := range m { 
  9.         println(k, v) 
  10.     } 

具體原因大家可以看一下源碼:map.go:mapiterinit,就會發(fā)現(xiàn)下邊這個代碼用來決定從哪開始遍歷map。另一個原因是map 在某些特定情況下(例如擴容),會發(fā)生key的搬遷重組。而遍歷的過程,就是按順序遍歷bucket,同時按順序遍歷bucket中的key。搬遷后,key的位置發(fā)生了重大的變化,所以遍歷map的結果就不可能按原來的順序了。

  1. func mapiterinit(t *maptype, h *hmap, it *hiter) { 
  2.         ...... 
  3.     // decide where to start 
  4.     r := uintptr(fastrand()) 
  5.         ...... 

 

責任編輯:武曉燕 來源: NoSay
相關推薦

2020-09-15 08:46:26

Kubernetes探針服務端

2017-05-05 08:12:51

Spark共享變量

2021-09-03 11:15:18

場景sql配置

2022-01-07 11:48:59

RabbitMQGolang 項目

2024-04-01 08:05:27

Go開發(fā)Java

2015-09-07 10:15:53

移動端開發(fā)

2023-03-06 07:50:19

內存回收Go

2023-03-13 13:36:00

Go擴容切片

2022-07-31 23:05:55

Go語言短變量

2023-01-18 23:20:25

編程開發(fā)

2024-01-06 08:16:19

init?函數數據開發(fā)者

2022-11-01 18:29:25

Go語言排序算法

2021-09-07 15:16:04

鴻蒙HarmonyOS應用

2023-02-20 08:11:04

2022-01-03 20:13:08

Gointerface 面試

2022-08-08 08:31:55

Go 語言閉包匿名函數

2022-08-08 06:50:06

Go語言閉包

2024-01-04 07:49:00

Go語言方法

2024-04-10 08:39:56

BigDecimal浮點數二進制

2023-09-22 11:29:11

JavasubList
點贊
收藏

51CTO技術棧公眾號