Go解坑指南
日常踩坑:for-range
这个循环会停止吗?
1 | func main() { |
先来看看for-range(two-value)底层实现
1 | for_temp := v // for_temp是slice v的值拷贝 |
所以,上述的代码只会循环3次。
再来个常见的,copys数组里是什么?["alice", "bob"]
?
1 | var dogs = []Dog{} |
答案
["bob", "bob"]
原因
d是一个临时变量,在循环开始前声明,d会被重复利用。
扩展:map的for-range是怎样的呢?为什么是无序的?
1 | for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) { |
但是,迭代出来的相对位置是固定的。
深度解惑:defer
- 优雅的释放资源或关闭
- 与recover配合捕获程序异常
- 结合闭包在return前做一些处理
- …
函数f1
与f2
的返回值分别是什么?
1 | func f1() (result int) { |
解答上述问题,需要了解这些知识
- defer原理
- Go闭包
- 逃逸分析(escape analyze)
defer原理
defer的对象一定是函数调用
defer的函数调用顺序LIFO(后进先出)
defer与return的关系:return语句并不是原子指令,可以分解为以下3条语句:
1
2
3返回值 = xxx
调用defer函数
空的return
Go闭包
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)1 | func f(i int) func() int { |
1 | c1 := f(0) |
逃逸分析(escape analyze)
1 | func getCursor() *Cursor { |
编译器会识别出变量需要在堆上分配。
分享一段defer+闭包的实战代码
1 | var code string |
错觉瞬间:Go到底有没引用?
错觉1
1 | func test(s []int) { |
输出[999 2 3],s被修改了!引用实锤!
错觉2
1 | func test(s []int) { |
输出[1 2 3],s没被修改,那究竟还是不是引用呢?
其实,它只是一个指针
1 | type slice struct { |
另外,Go的函数传参是值传递的。
There is no pass-by-reference in Go
— Dave Cheney