GO常見的錯誤99%程序員會遇到

介紹

新學習go語言的人可能遇到常見的錯誤,其中有兩個比較常見的錯誤,須要單獨拿出來講下,爲何要單獨說呢,由於這兩個錯誤跟其餘語言不一樣,是由於go自己的設計形成的。git

在循環(迭代)中使用了變量的引用

在go語言中,循環(迭代)所使用的變量是同一個變量,只是在每次循環的時候被賦於不一樣的值,這樣的作的目的呢,固然是出於高效考慮咯。可是,若是使用不當的話,可能會引發意想不到的行爲。程序員

舉一個栗子:github

func main() {
	var out []*int
	for i := 0; i < 3; i++ {
		out = append(out, &i)
	}
	fmt.Println("Values:", *out[0], *out[1], *out[2])
	fmt.Println("Addresses:", out[0], out[1], out[2])
}

複製代碼

上面的代碼會輸出:golang

Values: 3 3 3
Addresses: 0x40e020 0x40e020 0x40e020
複製代碼

由於每次循環中,咱們只是把變量 i 的地址放進 out 數組裏,由於變量 i 是同一個變量,只有在循環結束的時候,被賦值爲3。數組

解決方法:申明一個新的變量bash

for i := 0; i < 3; i++ {
	i := i // Copy i into a new variable.
 	out = append(out, &i)
 }
複製代碼

結果併發

Values: 0 1 2
Addresses: 0x40e020 0x40e024 0x40e028
複製代碼

同理對於切片來講,也用有這個問題,由於切片自己就只是一個地址而已app

func main() {
	var out [][]int
	for _, i := range [][1]int{{1}, {2}, {3}} {
		out = append(out, i[:])
	}
	fmt.Println("Values:", out)
}
複製代碼

結果:oop

Values: [[3] [3] [3]]
複製代碼

一樣的問題,在循環裏使用協程也會遇到學習

在協程中使用循環變量

按照程序員的思惟,都喜歡使用併發,你可能會寫出下面的代碼: 內心特別開心,原來go 的併發這麼簡單。

for _, val := range values {
	go func() {
    	fmt.Println(val)
	}()
}
複製代碼

可是,你可能會發現輸出的結果是一摸同樣的! 由於go的協程跑起來也是須要一點時間的,循環結束的時候,可能一個goroute都沒有跑完,而後 val 值確被賦值了,因此,你會看到,輸出的都是最後一個值

解決方法:

for _, val := range values {
	go func(val interface{}) {
		fmt.Println(val)
	}(val)
}
複製代碼

固然也能夠

for i := range valslice {
	val := valslice[i]
	go func() {
		fmt.Println(val)
	}()
}
複製代碼

Reference:github.com/golang/go/w…

相關文章
相關標籤/搜索