匿名返回值与剧名返回值的坑
在深入defer(续)中我们已经列举了匿名返回值与具名返回值产生的疑惑,并在defer与return到底谁先执行?中通过汇编代码的角度进行了解答。
package main
import "log"
func main() {
log.Println(testA())
log.Println(testB())
}
func testA() int {
a:=1
defer func() {
a=2
}()
return a
}
func testB() (a int) {
a=1
defer func() {
a=2
}()
return a
}
# out
1
2
避坑:避免在开发中使用这种让人产生疑惑的用法
闭包的坑
package main
import "log"
func main(){
for i:=1;i<5;i++{
defer func() {
log.Println(i)
}()
}
}
# out
5
5
5
5
正确的写法
package main
import "log"
func main(){
for i:=1;i<5;i++{
defer func(a int) {
log.Println(a)
}(i)
}
}
# out
4
3
2
1
开发时不要再循环中使用defer,defer定义的函数需要压栈,还要为存储defer申请额外的内存,所以循环中能不适用defer的,尽量不用
使用函数做参数的坑
package main
import "log"
func main(){
defer log.Println(test())
log.Println(2)
}
func test() int {
log.Println(3)
return 1
}
# out
3
2
1
defer定义的函数如果包含函数参数,defer在压栈之前会将函数参数先执行,将执行结果随defer定义的函数一起压栈
os.Exit导致defer不会被调用
os.Exit函数并不常用,但是应该知道,它会出现的位置直接退出
package main
import (
"log"
"os"
)
func main(){
defer func() {
log.Println(1)
}()
os.Exit(1)
}
# out
什么都没有输出
避坑:确保你了解os.Exit的作用,并能在合适的时候使用它,尽量使用return结束方法
总结
- 不要在defer函数中使用defer函数之外定义的变量,如果要使用尽量传递进去
- 不要再循环语句中使用defer函数
- 不要再defer函数中使用函数作为参数
每种语言都有自己的不好的地方,在使用过程中,要知道问题所在,但努力避免使用,不要明知有坑还不填坑