golang经典错误
1.变量遮蔽带来的非意料行为
func getA() (int, error) {
return 3, errors.New("getAError")
}
func main() {
var a int
var err error
if true {
a, err := getA() //新的代码块会产生新的变量
fmt.Println(a, err)
}
fmt.Println(a, err)
}
输出
3 getAError
0 <nil>
func main2() {
var a int
var err error
a, err := getA() //同一个代码块内,必须有一个新变量才能用:=
fmt.Println(a, err)
fmt.Println(a, err)
}
func getA() (int, error) {
return 3, errors.New("getAError: invalid")
}
2. delete不能删除NaN的key
delete 删除的KEY必须是可以自反的,NaN!=NaN,所以不能删除
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
clear(s)
fmt.Println(s) // [0 0 0]
a := [4]int{5, 6, 7, 8}
clear(a[1:3])
fmt.Println(a) // [5 0 0 8]
m := map[float64]float64{}
x := 0.0
m[x] = x
x /= x // x变成了NaN
m[x] = x
fmt.Println(len(m)) // 2
for k := range m {
delete(m, k) //给的NaN的Key,但是删不掉
}
fmt.Println(len(m)) // 1
clear(m)
fmt.Println(len(m)) // 0
}
[0 0 0]
[5 0 0 8]
2
1
0
3.go map存在内存泄露
如果我们频繁插入数据然后频繁删除,最后导致map可能内存泄露,因为delete操作不会真正地删除,而是将对应位置的数据清零.但没有从内存删除.存储桶还在.
clear进行清空操作,且能删除NaN的Key,不像delete.但是clear同样不能避免map内存泄露
func main() {
PrintMemUsage()
m := map[int][1024 * 1024]int8{}
for i := 0; i < 1024; i++ {
m[i] = [1024 * 1024]int8{}
}
PrintMemUsage()
for i := 0; i < 1024; i++ {
delete(m, i)
}
PrintMemUsage()
fmt.Println(len(m))
runtime.KeepAlive(m)
time.Sleep(1000000 * time.Millisecond)
}
func PrintMemUsage() {
runtime.GC()
var m runtime.MemStats
runtime.ReadMemStats(&m)
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
fmt.Printf("\tFrees = %v\n", m.Frees)
println("------------")
}
func bToMb(b uint64) uint64 {
return b / 1024 / 1024
}