Golang的坑

坑1. 延迟函数参数实时解析

func main() {
     a()
}
func a() {
    i := 1
    defer fmt.Println(i)
    i++
}

程序执行的最终结果是 1

进阶版:

type X struct {
	Num int
}

func main() {
	i := &X{Num: 2}
	fmt.Printf("0x0000: %p
", i)

	defer fmt.Println("0x0050:", *i)
	defer fmt.Printf("0x0040: %p
", i)
	defer func() {
		fmt.Println("0x0032:", i.Num)
		fmt.Printf("0x0033: %p
", i)
	}()

	defer func(p *X) {
		fmt.Println("0x0031:", i.Num)
	}(i)
	defer fmt.Println("0x0030:", i)
	i.Num++

	fmt.Println("0x0010:", i.Num)
	fmt.Printf("0x0011: %p
", i)

	i = &X{Num: 99}
	fmt.Println("0x0021:", i.Num)
	fmt.Printf("0x0022: %p
", i)
}

 程序执行的最终结果是

0x0000: 0xc0000a0000
0x0010: 3
0x0011: 0xc0000a0000
0x0021: 99
0x0022: 0xc0000aa000
0x0030: &{3}
0x0031: 99
0x0032: 99
0x0033: 0xc0000aa000
0x0040: 0xc0000a0000
0x0050: {2}

坑2. 延迟函数在匿名返回值和命名返回值函数中的不同表现

func main() {
    fmt.Println(a())
    fmt.Println(b())
}

func a() int {
    var i int
    defer func() {
        i++
    }()
    return i
}

func b() (i int) {
    defer func() {
    i++
    }()
    return i
}

程序执行的最终结果是 0 1

在a函数中,可以理解成Go自动创建了一个返回值 retValue,相当于执行retValue = i,然后检查是否有defer,如果有则执行,再返回刚才创建的返回值retValue

在b函数中,由于返回值在方法定义时已经被定义,所以没有创建retValue的过程,i就是retValue,defer对于result的修改也会被直接返回

坑3.程序退出时延迟函数不会被执行

func main() {
    fmt.Println("1")
    defer fmt.Println("0")
    os.Exit(0)
}

程序执行的最终结果是1

坑4. 字典的操作不是原子操作

有并发需求时使用 sync.Map

坑5, 接口值的返回总是非nil的

底层的interface实现是有一个类型一个内部值,只有在内部值和类型都未设置时(nil, nil),一个接口的值才为 nil

func main() {
    err := FindALL()
    if err != nil {
        fmt.Println(1)
    }
    if err.(*MyErr) != nil {
        fmt.Println(2)
    }
}

type MyErr struct {
}
func (m *MyErr) Error() string {
    return ""
}
func FindALL() error {
    var p *MyErr
    return p
}

坑6. 字符串时注意

删除字符串首尾时使用 

strings.TrimPrefix() strings.TrimSuffix()  

而不是

strings.TrimLeft() strings.TrimRight()

TrimLeft 从左开始, 如果发现了不在cutset中的字符, 就从这个点返回  

坑7 单例时注意

官方推荐方式为

var once sync.Once
once.Do(func() {
})

如果同一目录下,要声明两个单例时, once变量不能重复使用

8

https://studygolang.com/articles/2915

注意stop 和 reset

技巧1: JSON解析不输出

结构体增加tag可以在结构体的字段为nil时不输出

`json:"omitempty"`

技巧2: JSON延迟解析

json.RawMessage

坑8. 原生sql.Open 默认只是检查下链接字符串是不是正确的, 要检查是否连接上用connect 或者 open完了之后ping

参考链接:

https://golang.org/doc/faq#atomic_maps

golang中defer的使用规则

关于 Go defer 对匿名返回值和命名返回值的不同行为

Go语言中defer的一些坑

https://golang.org/doc/faq#nil_error

Go中error类型的nil值和nil

https://wrfly.kfd.me/posts/go-trimleft-and-trimprefix/

原文地址:https://www.cnblogs.com/restful/p/10913818.html