Golang的FAQ

本文大概总结了本人在 Golang 编程工作中遇到的疑难点, 最后更新于 20190516

延迟函数

延迟函数defer就是在函数调用返回后添加的函数调用

坑1. 延迟函数参数实时解析
func main() {
    a()
}
func a() {
   i := 1
   defer fmt.Println(i)
   i++
}

程序执行的最终结果是 1

虽然我们在 defer后面定义的是一个带变量的函数 fmt.Println(i) 但这个变量idefer被声明的时候,就已经确定为确定的值了, 相当于fmt.Println(0)

坑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

参考链接:

  1. golang中defer的使用规则
  2. 关于 Go defer 对匿名返回值和命名返回值的不同行为
  3. Go语言中defer的一些坑

字典

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

参考链接:

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

interface与nil

坑1, 接口值的返回总是非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
}

程序执行的最终结果是1

参考链接:

  1. https://golang.org/doc/faq#nil_error
  2. Go中error类型的nil值和nil
上一篇:golang之defer


下一篇:GO的defer深入理解